2012-10-05 71 views
98

我很好奇,爲什麼go不會將[]T轉換爲[]interface{},因爲它會隱式地將T轉換爲interface{}。這種轉換有什麼不重要的東西,我錯過了嗎?轉換接口片的轉換

實施例:

func foo([]interface{}) { /* do something */ } 

func main() { 
    var a []string = []string{"hello", "world"} 
    foo(a) 
} 

go build抱怨

不能使用(類型[]字符串)作爲類型[]接口{}函數自變量

如果我嘗試明確地做,同樣的事情:b := []interface{}(a)抱怨

不能轉換(類型[]字符串)鍵入[]接口{}

所以每次我需要做這種轉換(這似乎來了很多)的時候,我一直在做像這樣:

b = make([]interface{}, len(a), len(a)) 
for i := range a { 
    b[i] = a[i] 
} 

有沒有更好的方法來做到這一點,或標準庫函數來幫助這些轉換?每次我想調用一個函數時,寫出4行額外的代碼看起來很愚蠢。整數或字符串。

+0

這樣定義「隱式轉換[] T,爲[]接口{}」來表示「分配一個新的切片,並在複製的所有元素」。這與「將T隱式轉換爲接口{}」不一致,它只是與更通用的靜態類型相同的值;沒有被複制;如果你鍵入 - 斷言它回到類型T,你仍然會得到相同的東西。 – newacct

+0

沒有詳細考慮如何實現,只是在更高層次上,能夠輕鬆地將整個列表轉換爲另一種類型作爲不具有泛型類型的解決方法。 – danny

+0

好問題。 :) – weberc2

回答

104

在Go中,有一條通用規則,即語法不應隱藏複雜/昂貴的操作。在O(1)時間完成將string轉換爲interface{}。將[]string轉換爲interface{}也在O(1)時間完成,因爲切片仍然是一個值。但是,將[]string轉換爲[]interface{}的時間是O(n),因爲切片的每個元素都必須轉換爲interface{}

此規則的一個例外是轉換字符串。將string轉換爲[]byte[]rune時,即使轉換爲「語法」,Go也會運行O(n)。

沒有標準的庫函數會爲你做這種轉換。你可以用反射來製作一個,但它會比三線選項慢。

例與反思:

func InterfaceSlice(slice interface{}) []interface{} { 
    s := reflect.ValueOf(slice) 
    if s.Kind() != reflect.Slice { 
     panic("InterfaceSlice() given a non-slice type") 
    } 

    ret := make([]interface{}, s.Len()) 

    for i:=0; i<s.Len(); i++ { 
     ret[i] = s.Index(i).Interface() 
    } 

    return ret 
} 

你最好的選擇,雖然只是利用你在你的問題給出的代碼行:

b := make([]interface{}, len(a)) 
for i := range a { 
    b[i] = a[i] 
} 
+2

它可能會更慢,但它可以與任何類型的切片一起工作 – newacct

+0

這整個答案適用於「地圖」太btw。 – RickyA

+0

接口,不是接口。真是個絕招:) – Jacob

3

嘗試用interface{}代替。要退後一步,請嘗試

func foo(bar interface{}) { 
    s := bar.([]string) 
    // ... 
} 
+2

這引出了下一個問題:那麼OP如何在'bar'上迭代以便將其解釋爲「任何類型的切片」?請注意,他的三行代碼創建了一個'[] interface {}',而不是'[] string'或其他具體類型的片段。 – kostix

+5

-1:這隻適用於bar是[]字符串的情況,在這種情況下,你可以寫下:'func foo(bar [] string){/ * ... * /}' – weberc2

+1

使用類型開關,或在接受的答案中使用反射。 – dskinner

33

你缺少的事情是,Tinterface{}其值爲T在內存中具有不同的表示,因此不能進行簡單的轉換。

T類型的變量只是它在內存中的值。沒有關聯的類型信息(在Go中,每個變量在編譯時都有一個已知類型,而不是在運行時)。它在存儲器表示這樣的:

一種interface{}保持T類型的變量被表示在存儲器這樣

  • 指針輸入T

所以回到你原來的問題:爲什麼不會將[]T轉換爲[]interface{}

[]T轉換爲[]interface{}將涉及創建一個interface {}值的新分片,這是一個非平凡的操作,因爲內存中的佈局完全不同。

+2

感謝您真正解釋問題的要點 – kostix

+4

這是一個內容翔實且寫得很好的(+1),但您沒有解決他的問題的其他部分:「有沒有更好的方法來做到這一點...」( - 1)。 – weberc2