Go Wiki:InterfaceSlice
简介
鉴于您可以将任何类型的变量分配给 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{}
占用两个字(一个字表示包含内容的类型,另一个字表示包含的数据或指向该数据的指针)。因此,长度为 N 且类型为 []interface{}
的切片由 N*2 个字长的数据块作为后盾。
这与具有类型 []MyType
且长度相同的切片所支持的数据块不同。其数据块将为 N*sizeof(MyType) 个字长。
结果是您无法快速将类型为 []MyType
的内容分配给类型为 []interface{}
的内容;它们背后的数据看起来就是不同。
我还能做些什么?
这取决于你最初想做什么。
如果你想要一个任意数组类型的容器,并且计划在执行任何索引操作之前将其更改回原始类型,则可以使用 interface{}
。代码将是通用的(如果不是编译时类型安全的话),而且速度很快。
如果你真的想要一个 []interface{}
,因为你将在转换回之前进行索引,或者你正在使用一个特定的接口类型并且你想要使用它的方法,那么你将不得不复制该切片。
var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
interfaceSlice[i] = d
}
此内容是 Go Wiki 的一部分。