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