2016-10-07 49 views
4

我很好奇開箱切片片段並將它們作爲參數發送給可變參數函數。開箱切片片段

比方說,我們有一個可變參數參數的函數:

func unpack(args ...interface{}) 

如果我們wan't在它的工作原理接口片來傳遞,它不一樣,如果我們解開與否無關緊要:

slice := []interface{}{1,2,3} 
unpack(slice) // works 
unpack(slice...) // works 

如果我們有一片切片就會變得棘手。在這裏,編譯器不會讓我們傳遞一個解壓的版本:

sliceOfSlices := [][]interface{}{ 
    []interface{}{1,2}, 
    []interface{}{101,102}, 
} 
unpack(sliceOfSlices) // works 
unpack(sliceOfSlices...) // compiler error 

錯誤說:

不能使用sliceOfSlices(鍵入[] []接口{})類型[]接口{ }在參數解包

我不知道爲什麼會發生這種情況,因爲我們可以清楚地通過[]interface{}類型進入函數。我怎樣才能用解壓後的內容sliceOfSlices作爲參數來調用解壓方法?

遊樂場例如:https://play.golang.org/p/O3AYba8h4i

回答

5

這是覆蓋在Spec: Passing arguments to ... parameters

如果f是可變參數與...T類型的最後一個參數p,然後內fp類型是相當於類型[]T

...

如果最後一個參數被分配給一個片類型[]T,如果參數跟隨...可以通過不變的...T參數的值。在這種情況下,不會創建新切片。

在短所以:是編譯時錯誤,因爲sliceOfSlices(這是[][]interface{}類型的)不能被分配給args(這是[]interface{}型的)(proof on Playground)。

在長:

在你的第一個例子,當你做unpack(slice),因爲unpack()預計interface{}值,因此slice(這是[]interface{}型)將被包裹在一個interface{}值,它將作爲單個參數傳遞。

當你做unpack(slice...),這將作爲單獨的值通過slice的所有值到unpack();這是可能的,因爲slice的類型是[]interface{},它匹配可變參數的類型(args ...interface{})。

在你的第二個例子,當你unpack(sliceOfSlices)再次sliceOfSlices將被包裹在一個interface{}值和作爲參數傳遞。

但是當你嘗試unpack(sliceOfSlices...),那會想的sliceOfSlices每個元素傳遞給unpack(),但類型的sliceOfSlices(這是[][]interface{})不匹配一個可變參數的類型,因此編譯時錯誤。

通過sliceOfSlicesunpack()的唯一途徑「爆炸」是創建一個新的切片,其類型必須是[]interface{},複製的元素,那麼你可以使用...通過。

實施例:

var sliceOfSlices2 []interface{} 
for _, v := range sliceOfSlices { 
    sliceOfSlices2 = append(sliceOfSlices2, v) 
} 

unpack(sliceOfSlices2...) 

嘗試在Go Playground

讓我們用下面的unpack()函數來驗證的參數個數:

func unpack(args ...interface{}) { 
    fmt.Println(len(args)) 
} 

運行您的示例(和我的新片創作),輸出爲:

1 
3 
1 
2 

沒有...這證明只傳遞一個參數(包裝在interface{}中),並且使用...所有元素將分別傳遞。

Go Playground上嘗試此測試。