一尘不染

打开切片切片

go

我很好奇拆包切片并将其作为参数发送给可变参数函数。

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

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参数的解压缩内容调用解压缩方法?

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


阅读 259

收藏
2020-07-02

共1个答案

一尘不染

规范中对此进行了介绍:将参数传递给…
parameters

如果f为带有最终p类型为type的可变参数...T,则f类型内p等于type []T

如果最终参数可分配给切片类型[]T...T则在参数后跟时可以将其作为参数的值原样传递...在这种情况下,不会创建新的切片。

因此,在短期:
这是一个编译时错误,因为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...)时,可能希望将的每个元素传递sliceOfSlicesunpack(),但sliceOfSlices[][]interface{}的类型)与可变参数的类型不匹配,因此会产生编译时错误。

传递sliceOfSlicesunpack()“爆炸”
的唯一方法是创建一个新切片,其类型必须为[]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上尝试此测试。

2020-07-02