2016-10-07 27 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上尝试此测试。