打开切片切片

lma*_*gon 4 variadic-functions go slice

我很好奇解压缩切片并将它们作为参数发送到可变参数函数.

假设我们有一个带可变参数的函数:

func unpack(args ...interface{})
Run Code Online (Sandbox Code Playgroud)

如果我们不想传递它所使用的接口片段,那么如果我们解压缩它并不重要:

slice := []interface{}{1,2,3}
unpack(slice) // works
unpack(slice...) // works
Run Code Online (Sandbox Code Playgroud)

如果我们有一片切片,它会变得棘手.这里编译器不允许我们传入一个解压缩版本:

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

错误说:

不能使用sliceOfSlices(type [] [] interface {})作为类型[] interface {}在解压缩的参数中

我不知道为什么会发生这种情况,因为我们可以清楚地将一个[]interface{}类型传递给函数.如何使用aspacked内容sliceOfSlices作为参数调用方法解压缩?

游乐场示例:https://play.golang.org/p/O3AYba8h4i

icz*_*cza 5

这是覆盖在规格:将参数传递给...参数:

如果f是具有p类型的最终参数的可变参数...T,则在f类型内p等效于类型[]T.

...

如果最终参数可分配给切片类型[]T,则可以将其作为...T参数的值(如果参数后跟参数)保持不变....在这种情况下,不会创建新切片.

所以简而言之:它是一个编译时错误,因为sliceOfSlices(属于类型[][]interface{})无法分配args(类型[]interface{})(Playground上的证明).

长期:

在你的第一个例子中unpack(slice),因为unpack()期望值(interface{}因此slice类型[]interface{})将被包装在一个 interface{}值中,并且它将作为单个参数传递.

当你这样做时unpack(slice...),这会将所有值slice作为单独的值传递给unpack(); 这是可能的,因为类型slice[]interface{},它匹配variadic参数(args ...interface{})的类型.

在你的第二个例子中,当你这样做unpack(sliceOfSlices)时,sliceOfSlices将再次包装一个 interface{}值并作为单个参数传递.

但是当你尝试unpack(sliceOfSlices...),是想要通过的每一个元素sliceOfSlicesunpack(),但类型sliceOfSlices(这是[][]interface{})不匹配一个可变参数的类型,因此编译时错误.

传递sliceOfSlicesunpack()"爆炸" 的唯一方法是创建一个新的切片,其类型必须是[]interface{},复制元素,然后您可以使用它....

例:

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

unpack(sliceOfSlices2...)
Run Code Online (Sandbox Code Playgroud)

Go Playground尝试一下.

让我们使用以下unpack()函数来验证参数的数量:

func unpack(args ...interface{}) {
    fmt.Println(len(args))
}
Run Code Online (Sandbox Code Playgroud)

运行您的示例(并使用我的新切片创建),输出为:

1
3
1
2
Run Code Online (Sandbox Code Playgroud)

这证明...不仅传递一个参数(包装interface{}),并且使用...所有元素将分别传递.

Go Playground上试试这个测试.