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