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