我很好奇拆包切片并将其作为参数发送给可变参数函数。
假设我们有一个带有可变参数的函数:
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(类型[] [] interface {})用作类型[] interface {}
我不知道为什么会这样,因为我们可以清楚地将[]interface{}类型传递给函数。如何用sliceOfSlicesas参数的解压缩内容调用解压缩方法?
[]interface{}
sliceOfSlices
游乐场示例:https : //play.golang.org/p/O3AYba8h4i
规范中对此进行了介绍:将参数传递给… parameters:
如果f为带有最终p类型为type的可变参数...T,则f类型内p等于type []T。 … 如果最终参数可分配给切片类型[]T,...T则在参数后跟时可以将其作为参数的值原样传递...。在这种情况下,不会创建新的切片。
如果f为带有最终p类型为type的可变参数...T,则f类型内p等于type []T。
f
p
...T
[]T
…
如果最终参数可分配给切片类型[]T,...T则在参数后跟时可以将其作为参数的值原样传递...。在这种情况下,不会创建新的切片。
...
因此,在短期: 这是一个编译时错误,因为sliceOfSlices(这是类型的[][]interface{})不能被分配到args(这是类型[]interface{})(上游乐场证明)。
[][]interface{}
args
总而言之:
在第一个示例中,当您执行时unpack(slice),由于unpack()期望的值interface{},因此slice(类型为[]interface{})将被包装为 新 interface{}值,并将其作为 单个 参数传递。
unpack(slice)
unpack()
interface{}
slice
完成后unpack(slice...),这会将所有的值slice作为单独的值传递给unpack();; 这是可能的,因为的类型slice为[]interface{},它与可变参数(args ...interface{})的类型匹配。
unpack(slice...)
args ...interface{}
在第二个示例中,当您执行unpack(sliceOfSlices)时,sliceOfSlices将再次包装在 新 interface{}值中并作为 单个 参数传递。
unpack(sliceOfSlices)
但是,当您尝试unpack(sliceOfSlices...)时,可能希望将的每个元素传递sliceOfSlices给unpack(),但sliceOfSlices([][]interface{}的类型)与可变参数的类型不匹配,因此会产生编译时错误。
unpack(sliceOfSlices...)
传递sliceOfSlices给unpack()“爆炸” 的唯一方法是创建一个新切片,其类型必须为[]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上尝试此测试。