【问题标题】:Unpacking slice of slices拆开切片切片
【发布时间】:2017-02-16 06:54:48
【问题描述】:

我很想解开切片切片并将它们作为参数发送给可变参数函数。

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

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

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

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

【问题讨论】:

    标签: go slice variadic-functions


    【解决方案1】:

    Spec: Passing arguments to ... parameters:

    对此进行了介绍

    如果f 是带有...T 类型的最终参数p 的可变参数,则在fp 的类型等效于[]T 类型。

    ...

    如果最后一个参数可分配给切片类型[]T,如果参数后跟...,它可以作为...T 参数的值原封不动地传递。 在此如果没有创建新切片。

    简而言之:这是一个编译时错误,因为sliceOfSlices[][]interface{} 类型)不能分配给args[]interface{} 类型) (proof on Playground)。

    长篇大论:

    在您的第一个示例中,当您执行 unpack(slice) 时,由于 unpack() 需要 interface{} 的值,因此 slice(类型为 []interface{})将被包装在 new interface{} 值,它将作为单个参数传递。

    当您执行unpack(slice...) 时,这会将slice 的所有值作为单独的值传递给unpack();这是可能的,因为slice 的类型是[]interface{},它与可变参数(args ...interface{})的类型相匹配。

    在第二个示例中,当您执行 unpack(sliceOfSlices) 时,sliceOfSlices 将再次包装在 interface{} 值中,并作为 单个 参数传递。

    但是当你尝试unpack(sliceOfSlices...)时,那会想要将sliceOfSlices的每个元素传递给unpack(),但是sliceOfSlices的类型(即[][]interface{})与可变参数的类型不匹配,因此编译时错误。

    sliceOfSlices“exploded”传递给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 上试试这个测试。

    【讨论】:

      猜你喜欢
      • 2021-02-11
      • 1970-01-01
      • 2015-09-02
      • 2011-06-13
      • 1970-01-01
      • 2012-11-10
      • 2021-11-26
      • 1970-01-01
      • 2019-11-29
      相关资源
      最近更新 更多