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