2014-01-24 64 views
3

我發現它很奇怪,爲什麼[]字符串不能轉換爲[] interface {}?爲什麼[]字符串無法轉換爲[] interface {} in golang

我覺得應該是有可能的,因爲:

  1. 他們都是片
  2. 的[]字符串是字符串,這當然是接口{}

,但在每一個元素下面的例子,這將是一個編譯錯誤

func f(args ...interface{}){ 

} 
s := []string{"ssd", "rtt"} 
f(s...) 

爲什麼語言無法完成自動轉換?

+0

Golang數組不支持協方差 - 請參閱http://stackoverflow.com/questions/3839335/any-sensible-solution-to-the-lack-of-array-slice-covariance-in-go?rq=1 ,http://stackoverflow.com/questions/19389629/golang-go-get-the-type-of-array – user2864740

+0

這在FAQ http://golang.org/doc/faq#convert_slice_of_interface中有描述。閱讀golang.org上提供的文檔不能過度推薦。 – Volker

+0

http://stackoverflow.com/q/12990338/727643的副本 –

回答

5

因爲[]string[]interface{}具有不同的內存中佈局。當你意識到interface{}變量需要知道它包含的值的類型時,這是顯而易見的。

對於[]string切片,後備陣列只需要保存單個字符串。對於[]interface{}切片,您同時具有類型信息和字符串值(以及指向字符串值的指針,因爲字符串比單個內存字大)。因此,從一種類型轉換到另一種類型將涉及複製數據。

Go會自動執行轉換會令人困惑,因爲它會導致難以推理代碼。例如,函數調用f(s)可以修改片段s中的字符串,前提是它聲明採用[]string參數,但如果聲明採用[]interface{}參數,則不會修改該片段中的字符串。

5

切片基本上只是對底層數組,開始指針,長度和容量的引用。因此,如果可能的話,請考慮以下幾點:

sliceOfStrings := []string{"one", "two", "three"} 
// prints ONE TWO THREE 
for i := range sliceOfStrings { 
    fmt.Println(strings.ToUpper(sliceOfStrings[i])) 
} 

// imagine this is possible 
var sliceOfInterface = []interface{}(sliceOfStrings) 
// since it's array of interface{} now - we can do anything 
// let's put integer into the first position 
sliceOfInterface[0] = 1 
// sliceOfStrings still points to the same array, and now "one" is replaced by 1 
fmt.Println(strings.ToUpper(sliceOfStrings[0])) // BANG! 

此問題存在於Java和C#中。實際上它很少發生,但仍然如此。假設在Go中不存在像int32 - > int64這樣的自動類型轉換,如果您確實想將[] string作爲[] interface {}發送,那麼您可以強制創建[] interface {}副本。這樣就不會有什麼驚喜 - 你明確地寫出來了,你知道你在做什麼。如果函數將修改[] interface {} - 它不會傷害原始[]字符串。