前言
本文翻译自InterfaceSlice
由于在go中,我们可以将任意一种类型的变量赋值给interface{},所以常常有人写下如下的代码
var dataSlice []int = foo()
var interfaceSlice []interface{} = dataSlice
但是,此代码会报错,错误信息如下
cannot use dataSlice (type []int) as type []interface { } in assignment
这就会引出一个问题,为什么我可以赋值任意类型的变量给interface{},而不能将任意的切片赋值给[]interface{}?
为什么?
主要有两个原因。
首先,[]interface{}类型的变量不是一个interface{},它是一个切片,其元素凑巧正好为interface{}。即使给出如此解答,也有人会说[]interface{}的含义是非常明显的。
好吧,确实是这样的吗?在运行时,一个[]interface{}类型的变量有一种特定的内存结构。
每个interface{}会包含两个值,一个指的是此元素的类型,另一个指的是此元素的值或者一个指向此元素值的指针。因而,一个类型为[]interface{}、长度为N的切片,背后支撑的数据长度是2*N个值。
[]interface{}和长度相同、类型为[]MyType背后的数据量是不同的,[]MyType的数据块的长度是N*sizeof(MyType)。
这就会造成你不能快速的将变量[]MyType赋值给[]interface{}。因为他们背后的数据并不相同。
应该怎样做?
这首先取决于你想怎么做。
如果你仅想要一个包含任意数组类型的容器,并且在把他们变回原来类型之前,不会使用索引的操作。你可以仅仅把[]MyType赋值给interface{}类型的变量。这种操作是非常普通和安全的。
如果你的确想要一个[]interface{},比如,在你想要在把变量变回原来类型之前,你需要使用索引;或者你使用的是一种特定类型的接口,需要使用接口的方法。那么你必须赋值一下切片。
var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
interfaceSlice[i] = d
}