关于go:打开切片切片

Unpacking slice of slices

我对解包一片切片并将其作为变量函数的参数发送感到好奇。

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

1
func unpack(args ...interface{})

如果我们不在一个接口片中传递它的工作状态,那么不管我们是否解包它:

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

如果我们有一片切片会很棘手。在这里,编译器不允许我们传递未打包的版本:

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

错误显示:

cannot use sliceOfSlices (type [][]interface {}) as type []interface {} in argument to unpack

我不知道为什么会发生这种情况,因为我们可以清楚地将[]interface{}类型传递到函数中。如何使用sliceOfSlices的解包内容调用方法unpack作为参数?

操场示例:https://play.golang.org/p/o3ayba8h4i


规范中包含了这一点:将参数传递给…参数:

If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T.

...

If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.

简而言之:这是一个编译时错误,因为sliceOfSlices(类型为[][]interface{}的)不能分配给args(类型为[]interface{}的)(操场上的证明)。

长:

在您的第一个示例中,当您执行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{}的类型)与变量参数的类型不匹配,因此会产生编译时错误。

sliceOfSlices传递给unpack()exploded的唯一方法是创建一个类型必须为[]interface{}的新片,复制元素,然后使用...传递它。

例子:

1
2
3
4
5
6
var sliceOfSlices2 []interface{}
for _, v := range sliceOfSlices {
    sliceOfSlices2 = append(sliceOfSlices2, v)
}

unpack(sliceOfSlices2...)

在运动场上试试。

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

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

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

1
2
3
4
1
3
1
2

没有...证明只有一个参数被传递(包装在interface{}中),使用...所有元素将被单独传递。

在游乐场上试试这个测试。