解包切片

时间:2016-10-07 09:55:42

标签: go slice variadic-functions

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

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

func unpack(args ...interface{})

如果我们不想传递一片界面,那么无论我们是否打开它都无关紧要:

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(type [] [] interface {})作为类型[] interface {}

我不知道为什么会这样,因为我们可以清楚地将[]interface{}类型传递给函数。如何使用解压缩的sliceOfSlices内容作为参数调用方法解压缩?

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

1 个答案:

答案 0 :(得分:5)

这涵盖在Spec: Passing arguments to ... parameters

  

如果f为变量型,其最终参数p的类型为...T,那么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{})与variadic参数的类型不匹配,因此编译时错误。

sliceOfSlices传递给unpack()&#34的唯一方法是爆炸"是创建一个类型必须为[]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上尝试此测试。