我很好奇解压缩切片并将它们作为参数发送到可变参数函数。
假设我们有一个带可变参数的函数:
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
内容作为参数调用方法解压缩?
答案 0 :(得分:5)
这涵盖在Spec: Passing arguments to ... parameters:
中如果
f
为变量型,其最终参数p
的类型为...T
,那么f
中p
的类型等同于[]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上尝试此测试。