go 接口 构造器_Go 中接口值的复制

我一直在思考 Go 语言它是如何工作的。直到最近我才发现 Go 中一切都是基于值的。当我们向函数传递参数、迭代切片、执行类型断言时我们都可以看到这一现象。在这些例子中,这些数据结构所存储的值的拷贝会被返回。当我刚开始学习 Go 的时候,我对于这种实现方式很失望,但渐渐地我开始意识到这样做对于我们的代码来说有它的合理性。

我开始在想,如果我创建了一个所存储的是值而非指针的接口类型的拷贝会发生什么。那么这个新的接口值会拥有自己新的副本值,还是共享原来的值?为了验证我的猜想,我写了一个小程序来检查接口值。

https://play.golang.org/p/KXvtpd9_29

清单 1

06 package main
07
08 import (
09     "fmt"
10     "unsafe"
11 )
12
13 // notifier provides support for notifying events.
14 type notifier interface {
15     notify()
16 }
17
18 // user represents a user in the system.
19 type user struct{
20     name string
21 }
22
23 // notify implements the notifier interface.
24 func (u user) notify() {
25     fmt.Println("Alert", u.name)
26 }

在清单 1 的代码中第 14 行,我们声明了一个具有 notify 方法的接口类型 notifier。在 19 行我们声明了一个 user 类型,这个类型在 24 行实现了 notifier 接口中的 notify 方法。现在我们拥有了一个接口类型和一个实现类型。

清单 2

28 // inspect allows us to look at the value stored
29 // inside the interface value.
30 func inspect(n *notifier, u *user) {
31     Word := uintptr(unsafe.Pointer(n)) + uintptr(unsafe.Sizeof(&u))
32     value := (**user)(unsafe.Pointer(word))
33     fmt.Printf("Addr User: %p  Word Value: %p  Ptr Value: %vn", u, *value, **value)
34 }

在清单 2 中我们在 30 行写了一个检查的函数。这个函数返回给我们一个指向接口值的第二个字的指针。通过这个指针我们可以检查此接口第二个字的值,以及第二个字指向的 user 值。我们需要审查这些值来真正理解接口的机制。

清单 3:

36 func main() {
37
38     // Create a notifier interface and concrete type value.
39     var n1 notifier
40     u := user{"bill"}
41
42     // Store a copy of the user value inside the notifier
43     // interface value.
44     n1 = u
45
46     // We see the interface has its own copy.
47     // Addr User: 0x1040a120  Word Value: 0x10427f70  Ptr Value: {bill}
48     inspect(&n1, &u)
49
50     // Make a copy of the interface value.
51     n2 := n1
52
53     // We see the interface is sharing the same value stored in
54     // the n1 interface value.
55     // Addr User: 0x1040a120  Word Value: 0x10427f70  Ptr Value: {bill}
56     inspect(&n2, &u)
57
58     // Store a copy of the user address value inside the
59     // notifier interface value.
60     n1 = &u
61
62     // We see the interface is sharing the u variables value
63     // directly. There is no copy.
64     // Addr User: 0x1040a120  Word Value: 0x1040a120  Ptr Value: {bill}
65     inspect(&n1, &u)
66 }

清单 3 展示了从 36 行开始的主函数。 我们做的第一件事情就是在 39 行声明了类型为 notifier 名为 n1 的接口变量,将其设为初始零值。然后在 40 行我们声明了一个类型为 user 的变量 u,其初始值为 bill

我们想要在将具体 user 值分配给接口之后,检查这个接口值的第二个字包含什么。

清单 4

42     // Store a copy of the user value inside the notifier
43     // interface value.
44     n1 = u
45
46     // We see the interface has its own copy.
47     // Addr User: 0x1040a120  Word Value: 0x10427f70  Ptr Value: {bill}
48     inspect(&n1, &u)

插图 1:当我们将 user 的值分配给该接口之后,这个接口内部结构是什么样的。

0e5f37fc2d672d9ad226af777c1937d9.png

插图 1 向我们展示了在分配后接口的内部结构视图。我们可以看到这个接口有它自己的 user 值的拷贝。存储在接口值内部的 user 值的地址和原始 user 值的地址并不相同。

我编写这段代码用来了解如果我创建了一个分配了值而非指针的接口值的副本会发生什么。新的接口值是否也有自己的副本,或者值是否会共享。

清单 5

50     // Make a copy of the interface value.
51     n2 := n1
52
53     // We see the interface is sharing the same value stored in
54     // the n1 interface value.
55     // Addr User: 0x1040a120  Word Value: 0x10427f70  Ptr Value: {bill}
56     inspect(&n2, &u)

插图 2:当接口值被拷贝后,这两个接口值的内部构造。

548bf29138f414650c0b9a11cb9e5145.png

插图 2 给了我们答案。当我们创建一个接口值的拷贝时,这就是我们复制的全部内容。原来存储在 n1 中的 user 值此时也共享给了 n2。每个接口值并没有获得它们独有的拷贝。它们共享了同一个 user 值。

如果我们分配的是 user 值的地址而不是该值本身,那么所有这些情况都会有所改变。

清单 6

58     // Store a copy of the user address value inside the
59     // notifier interface value.
60     n1 = &u
61
62     // We see the interface is sharing the u variables value
63     // directly. There is no copy.
64     // Addr User: 0x1040a120  Word Value: 0x1040a120  Ptr Value: {bill}
65     inspect(&n1, &u)

插图 3: 当我们为接口分配了一个地址时,该接口值的内部构造。

b79d7545c2dfedfffccf9a79361ff81b.png

在插图 3 中,我们看到该接口现在指向的是被变量 u 引用的 user 值。 变量 u 的地址已经存储到这个接口值的第二个字当中。这就意味着和 user 值相关的任何变化都会影响到这个接口值。

结论

我允许自己对 Go 在创建一个接口值的拷贝时,只存储值而不是指针的情况感到困惑。有那么一瞬间,我想知道接口值的每个副本是否也创建了接口引用的值的副本。因为我们“存储”了一个值而不是一个指针。但我们现在学到的是,由于地址始终会被存储起来,因此它是被复制的地址,而不是值的本身。


via:Go 中接口值的复制 - Go语言中文网 - Golang中文社区

作者:William Kennedy 译者:barryz 校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/487988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2010年下半年软件评測师(下午)试题分析与解答

真题二(14分):阅读下列说明,回答问题1至问题4,将解答填入答题纸的相应栏内。 说明:某软件公司在研发一个城镇居民保险系统时,为了加快进度,測试工作在系统开发初步完毕之后開始并直接…

【人工智能】人工智能革命与机遇

来源 | 北大AI公开课编辑 | Vincent、Natalie课程导师:雷鸣,天使投资人,百度创始七剑客之一,酷我音乐创始人,北京大学信科人工智能创新中心主任,2000年获得北京大学计算机硕士学位,2005年获得斯…

laravel log 对象_swoole运行模式加速laravel应用的详细介绍(life)

本篇文章给大家带来的内容是关于swoole运行模式加速laravel应用的详细介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。我的官方群点击此处。一、SwooleSwoole号称重新定义了PHP,它是一个PHP扩展,使…

OVS+DPDK Datapath 包分类技术

本文主体内容译于[DPDK社区文档],但并没有逐字翻译,在原文的基础上进行了一些调整,增加了对TSS分类器的详细阐述。 1. 概览 本文描述了OVSDPDK中的包分类器(datapath classifier -- aka dpcls)的设计与实现思路。本文的内容主要牵涉到分类器对…

前端学习笔记

文章目录 1、学习路线2、token的安全储存方案3、跨域4、相关的学习链接 前言:最近在学习前端补齐我的软件技能树,最近简单总结一下 1、学习路线 基本:vue3、ts(js)、 vite、eslint、css(动画、布局) 依赖包:vue-router、vue-i18…

mysql第五章 在线测试_PHP+MySQL来实现在线测试quiz功能

在上一篇文章中,我们介绍了jQuery前端PHP在线测试题效果。这篇文章将结合实例给大家介绍如何使用jQueryPHPMySQL来实现在线测试题,包括动态读取题目,答题完毕后台评分,并返回答题结果。查看演示下载资源:1332次 下载资…

深度揭秘AI换脸原理,为啥最先进分类器也认不出?

文章来源:VentureBeat,arXiv智东西4月20日消息,AI换脸已不是新鲜事,手机应用市场中有多款换脸app,此前也曾曝出有网络IP用明星的面孔伪造色情影片、在大选期间用竞选者的脸制作虚假影像信息等。为了规避Deepfake滥用带…

ASP.NET MVC中在 @RenderBody() 或者 @Html.Partial()中需要使用引入外部js,css

今天想在后台封装一下bootstraptree这个插件,引入jquery.js bootstrap.js bootstrap.css bootstrap-tree.js后,我在页面查看脚本错误就连最简单的 $(function(){ alert("test"); }) 经过一番查看,原来mvc在生成_layout的时候默认先…

用ubuntu远程连接mysql_Ubuntu 安装 MySQL 和远程连接

#安装MySQLsudo apt install mysql-server#进入数据库sudo mysql#修改密码ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123;产生用户不能授权的原因是mysql 数据库中user 表中的特定用户(root) 的host 的属性值为localhost.#查看select host, user fro…

中美德工业互联网路径比较

转自丨无锡情报所作者丨王喜文,九三学社中央促进技术创新工作委员会委员、九三学社中央科技委委员过去20年,互联网是改变社会、改变商业最重要的技术;如今,随着5G、物联网以及云计算和大数据、区块链、人工智能技术的迅速发展&…

不同浏览器隐藏默认表单样式

各种appearance: none; 转载于:https://www.cnblogs.com/haimingpro/p/7168738.html

jmeter file upload 变量_通达OA上传漏洞之变量覆盖分析

作者:kw0ng开始通达OA上传到包含漏洞分析的文章已经有很多,本文重点分析,文件上传处决定路径信息是否回显的UPLOAD_MODE参数是怎么传递的。代码分析触发文件上传点位于/ispirit/im/upload.php中,服务端在接收文件信息的同时还需要…

如果卷积神经网络存在根本性的缺陷,你会怎么看?

来源:人工智能头条作者 | Ben Dickson译者 | 香槟超新星经过一段漫长时期的沉寂之后,人工智能正在进入一个蓬勃发展的新时期,这主要得益于深度学习和人工神经网络近年来取得的长足发展。更准确地说,人们对深度学习产生的新的兴趣在…

cacls查看文件权限

PS C:\> cacls .\099260b8-7e81-4d4c-8970-c637011399bf.txt C:\099260b8-7e81-4d4c-8970-c637011399bf.txt BUILTIN\Administrators:(ID)FNT AUTHORITY\SYSTEM:(ID)FBUILTIN\Users:(ID)R F 表示完全控制C 表示更改W 表示写入R 表示读取借钱享受 祸患无穷http://v.youku.…

python语法基础整理_Python基础

Python是一种计算机编程语言。计算机编程语言和我们日常使用的自然语言有所不同,最大的区别就是,自然语言在不同的语境下有不同的理解,而计算机要根据编程语言执行任务,就必须保证编程语言写出的程序决不能有歧义,所以…

产业|嵌入式传感器将是未来机器人等技术增长的核心

来源:EEWORLD移动即服务(MaaS)被认为是智能移动的一个关键要素,而机器人汽车技术将是智能移动的一个重要因素,它又高度依赖于嵌入式传感器。根据市场研究和战略咨询公司Yole development pement (Yole)的预测,在这种情况下&#x…

vscode写java没有提示_VS Code报错Language Support for Java(TM)插件显示需要JDK11 写java代码没有提示...

鉴于IDEA的打开速度(电脑的垃圾),平常刷LeetCode都是在VSCode上,结果这几天老是打开给我报错Java 11 or more recent is required to run. Please download and install a recent JDK由于平常开发一直需要使用Java8,将环境变量改为JDK11是绝对…

1.6.2 多表插入

1.6.2 多表插入正在更新内容,请稍后 转载于:https://www.cnblogs.com/cxchanpin/p/7182943.html

可观测宇宙中,我们可能是唯一的生命

图片来源:Pixabay长期以来,人类一直渴望在宇宙中找到地外生命的痕迹,但一项于今年早些时候发表的研究,给持有此类想法的人泼了一盆冷水。基于“自然发生”学说以及其中的“RNA世界”假说,研究人员认为在可观测宇宙中&a…

MySQL占用系统进程_MySQL的Sleep进程占用大量连接解决方法

第一部分为产生大量sleep进程的原理及对应解决方法第二部分为设置wait_timeout值,有效减少sleep进程第一部分开始1、通常来说,MySQL出现大量Sleep进程是因为采用的PHP的MySQL长链接数据库方式,即使用了mysql_pconnect来打开链接数据库&#x…