go - slice slice 的拆包

标签 go slice variadic-functions

我很好奇解包 slice 并将它们作为参数发送给可变参数函数。

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

func unpack(args ...interface{})

如果我们不想传入它工作的接口(interface)片段,我们是否解压它并不重要:

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

如果我们有一片 slice ,它会变得棘手。这里编译器不允许我们传入解压后的版本:

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

错误说:

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

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

Playground 示例:https://play.golang.org/p/O3AYba8h4i

最佳答案

这包含在 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.

简而言之:这是一个编译时错误,因为 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{})与可变参数的类型不匹配,因此出现编译时错误。

sliceOfSlices 传递给 unpack() “exploded” 的唯一方法是创建一个新的 slice ,其类型必须是 []interface{} code>,复制元素,然后你可以使用...传递它。

例子:

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

unpack(sliceOfSlices2...)

Go Playground 上试试.

让我们使用下面的 unpack() 函数来验证参数的数量:

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

运行您的示例(以及我创建的新 slice ),输出为:

1
3
1
2

这证明没有 ... 只传递了一个参数(包装在 interface{} 中),并且使用 ... 所有元素将单独传递。

Go Playground 上尝试这个测试.

关于go - slice slice 的拆包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39914447/

相关文章:

c++ - 如何遍历 std::index_sequence

java - 使用变量参数在没有 ArrayList 的情况下查找数字的乘积?

java - 将 1 传递给多个相同对象类型的参数

variables - 如何通过包共享变量

gorm 多对一返回空

go - 在 OSX 上交叉编译 Go?

python - 在 tensorflow 中“分配”2D block 切片?

Go:根据关键字格式化字符串

go - 在给定索引处的 slice 中插入一个值

pointers - 将指针 slice 分配给它们实现的接口(interface) slice