当前位置: 首页 > 面试题库 >

打开切片切片

李景天
2023-03-14
问题内容

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

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

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


问题答案:

规范中对此进行了介绍:将参数传递给…
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上尝试此测试。



 类似资料:
  • 取一个list或tuple的部分元素是非常常见的操作。比如,一个list如下: >>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] 取前3个元素,应该怎么做? 笨办法: >>> [L[0], L[1], L[2]] ['Michael', 'Sarah', 'Tracy'] 之所以是笨办法是因为扩展一下,取前N个元素就没辙了。 取前N个元素

  • 举个例子 给你一个list 让你取前30个怎么办? a = [] # 很多数据 a[0],a[1] #按照这种方式吗?这也太复杂了! for i in a: pass ## 这种方式也是可以的,但是还是有点复杂了,在编程语言中,或者是我们的编程思想中,less is more是最重要的,也就是说,写的越少越好。 # 所以我们可以采用切片的方式 a[1:3],从第二个开始到第

  • 取一个list或tuple的部分元素是非常常见的操作。比如,一个list如下: >>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] 取前3个元素,应该怎么做? 笨办法: >>> [L[0], L[1], L[2]] ['Michael', 'Sarah', 'Tracy'] 之所以是笨办法是因为扩展一下,取前N个元素就没辙了。 取前N个元素

  • 在Go中,和之间有什么区别? 我发现两者都有效,但哪一个更好?

  • 切片是Go语言的关键类型之一,它提供了比数组更多的功能。 示例1: package main import "fmt" func main() { // 和数组不同的是,切片的长度是可变的。 // 我们可以使用内置函数make来创建一个长度不为零的切片 // 这里我们创建了一个长度为3,存储字符串的切片,切片元素 // 默认为零值,对于字符串就是""。 s

  • 7.2.1 概念 切片(slice)是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list 类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口。 切片是可索引的,并且可以由 len()