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 的一部分。