dongmei425373 2016-10-07 09:55
浏览 65
已采纳

打开切片切片

I am curious about unpacking a slice of slices and sending them as arguments to a variadic function.

Let's say we have a function with variadic parameters:

func unpack(args ...interface{})

If we wan't to pass in a slice of interfaces it works, it doesn't matter if we unpack it or not:

slice := []interface{}{1,2,3}
unpack(slice) // works
unpack(slice...) // works

It gets tricky if we have a slice of slices. Here the compiler doesn't let us pass in an unpacked version:

sliceOfSlices := [][]interface{}{
    []interface{}{1,2},
    []interface{}{101,102},
}
unpack(sliceOfSlices) // works
unpack(sliceOfSlices...) // compiler error

The error says:

cannot use sliceOfSlices (type [][]interface {}) as type []interface {} in argument to unpack

I don't know why this happens, as we can clearly pass an []interface{} type into the function. How can I call the method unpack with the unpacked content of sliceOfSlices as arguments?

Playground example: https://play.golang.org/p/O3AYba8h4i

  • 写回答

1条回答 默认 最新

  • duanhoupeng6642 2016-10-07 10:40
    关注

    This is covered in Spec: Passing arguments to ... parameters:

    If f is variadic with a final parameter p of type ...T, then within f the type of p is equivalent to type []T.

    ...

    If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.

    So in short: it is a compile-time error because sliceOfSlices (which is of type [][]interface{}) cannot be assigned to args (which is of type []interface{}) (proof on Playground).

    In long:

    In your first example when you do unpack(slice), since unpack() expects values of interface{}, therefore slice (which is of type []interface{}) will be wrapped in a new interface{} value, and it will be passed as a single argument.

    When you do unpack(slice...), this will pass all the values of slice as separate values to unpack(); this is possible because type of slice is []interface{}, it matches the type of the variadic parameter (args ...interface{}).

    In your second example when you do unpack(sliceOfSlices), again, sliceOfSlices will be wrapped in a new interface{} value and passed as a single argument.

    But when you try unpack(sliceOfSlices...), that would want to pass each element of sliceOfSlices to unpack(), but type of sliceOfSlices (which is [][]interface{}) does not match the type of the variadic parameter, hence the compile-time error.

    The only way to pass sliceOfSlices to unpack() "exploded" is to create a new slice whose type must be []interface{}, copy the elements, then you can pass it using ....

    Example:

    var sliceOfSlices2 []interface{}
    for _, v := range sliceOfSlices {
        sliceOfSlices2 = append(sliceOfSlices2, v)
    }
    
    unpack(sliceOfSlices2...)
    

    Try it on the Go Playground.

    Let's use the following unpack() function to verify the number of arguments:

    func unpack(args ...interface{}) {
        fmt.Println(len(args))
    }
    

    Running your example (and with my new slice creation), output is:

    1
    3
    1
    2
    

    Which proves without ... only a single argument is passed (wrapped in interface{}), and using ... all elements will be passed separately.

    Try this test on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 求解vmware的网络模式问题 别拿AI回答
  • ¥24 EFS加密后,在同一台电脑解密出错,证书界面找不到对应指纹的证书,未备份证书,求在原电脑解密的方法,可行即采纳
  • ¥15 springboot 3.0 实现Security 6.x版本集成
  • ¥15 PHP-8.1 镜像无法用dockerfile里的CMD命令启动 只能进入容器启动,如何解决?(操作系统-ubuntu)
  • ¥30 请帮我解决一下下面六个代码
  • ¥15 关于资源监视工具的e-care有知道的嘛
  • ¥35 MIMO天线稀疏阵列排布问题
  • ¥60 用visual studio编写程序,利用间接平差求解水准网
  • ¥15 Llama如何调用shell或者Python
  • ¥20 谁能帮我挨个解读这个php语言编的代码什么意思?