为什么 Go 不支持 []T 转换为 []interface

在 Go 中,如果 interface{} 作为函数参数的话,是可以传任意参数的,然后通过类型断言来转换。,举个例子:,不管是传 int​ 还是 string,最终都能输出正确结果。,那么,既然是这样的话,我就有一个疑问了,拿出我举一反三的能力。是否可以将 []T​ 转换为 []interface 呢?,比如下面这段代码:,很遗憾,这段代码是不能编译通过的,如果想直接通过 b := []interface{}(a) 的方式来转换,还是会报错:,正确的转换方式需要这样写:,本来一行代码就能搞定的事情,却非要让人写四行,是不是感觉很麻烦?那为什么 Go 不支持呢?我们接着往下看。,这个问题在官方 Wiki 中是有回答的,我复制出来放在下面:,The first is that a variable with type []interface{}​ is not an interface! It is a slice whose element type happens to be interface{}. But even given this, one might say that the meaning is clear. Well, is it? A variable with type []interface{}​ has a specific memory layout, known at compile time. Each interface{} takes up two words (one word for the type of what is contained, the other word for either the contained data or a pointer to it). As a consequence, a slice with length N and with type []interface{}​ is backed by a chunk of data that is N*2 words long. This is different than the chunk of data backing a slice with type []MyType​ and the same length. Its chunk of data will be N*sizeof(MyType)​ words long. The result is that you cannot quickly assign something of type []MyType​ to something of type []interface{}; the data behind them just look different.,大概意思就是说,主要有两方面原因:,下面就来详细说说,是怎么个不一样。,首先来看看 slice 在内存中是如何存储的。在源码中,它是这样定义的:,举个例子,创建如下一个切片:,那么它的布局如下图所示:,图片,假设程序运行在 64 位的机器上,那么每个「正方形」所占空间是 8 bytes。上图中的 ptr 所指向的底层数组占用空间就是 4 个「正方形」,也就是 32 bytes。,接下来再看看 []interface{} 在内存中是什么样的。,回答这个问题之前先看一下 interface{} 的结构,Go 中的接口类型分成两类:,源码中的定义分别如下:,具体细节我们不去深究,但可以明确的是,每个 interface{}​ 包含两个指针, 会占据两个「正方形」。第一个指针指向 itab​ 或者 _type;第二个指针指向实际的数据。,所以它在内存中的布局如下图所示:,图片,因此,不能直接将 []int64​ 直接传给 []interface{}。,接下来换一个更形象的方式,从程序实际运行过程中,看看内存的分布是怎么样的?,看下面这样一段代码:,我们使用 Delve 来进行调试,可以点击这里进行安装。,打印 is 的地址:,接下来看看 slice 在内存中都包含了哪些内容:,每行有 8 个字节,也就是上文说的一个「正方形」。第一行是指向数据的地址;第二行是 4,表示切片长度;第三行也是 4,表示切片容量。,再来看看指向的数据到底是怎么存的:,这就是一片连续的存储空间,保存着实际数据。,接下来用同样的方式,再来看看 iis 的内存布局。,切片的布局和 is 是一样的,主要的不同是所指向的数据:,仔细观察上面的数据,偶数行内容都是相同的,这个是 interface{}​ 的 itab 地址。奇数行内容是不同的,指向实际的数据。,打印地址内容:,很明显,通过打印程序运行中的状态,和我们的理论分析是一致的。,通过以上分析,我们知道了不能转换的原因,那有没有一个通用方法呢?因为我实在是不想每次多写那几行代码。,也是有的,用反射 reflect,但是缺点也很明显,效率会差一些,不建议使用。,还有其他方式吗?答案就是 Go 1.18 支持的泛型,这里就不过多介绍了,大家有兴趣的话可以继续研究。,以上就是本文的全部内容,如果觉得还不错的话欢迎点赞,转发和关注,感谢支持。,参考文章:

文章版权声明

 1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/19039.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年3月5日 上午12:00
下一篇 2023年3月7日 下午10:34