切片的疑问?

直接看代码

a := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9}

s := a[1:3:6]
fmt.Println(s, len(s), cap(s)) // [2 3]  2  5  实际地址包含有 [2, 3, 4, 5, 6]

s2 := s[3:]   // 为什么这里报越界错误???按我的理解,这里应该得到 [5, 6] 才对啊

s2 := s[1:]  // 这种可以正常执行
fmt.Println(s2, len(s2), cap(s2))  // [3] 1 4   按我的理解,应该得到 [3, 4, 5, 6]

s2 := s[3:5]  // 这种也可以执行, 按上面的执行结果来看,这种应该越界了啊
fmt.Println(s2, len(s2), cap(s2))   // [5 6] 2 2

切片的一些特性真是让人莫名其妙啊。

追加

再次测试代码,发现问题的原因:

切片的疑问?

再次理解:

  • 其实 s[3:] 等价于 s[3:len(s)],因为s的长度是2,所以这里溢出了。
  • s[1:] 等价于 s[1:len(s)],能取到索引。
  • s[3:5] 因为s的容量是5, 实际的索引地址支持到 【2,3,4,5,6】
  • 再比如,我也可以取 s[1:5]
本作品采用《CC 协议》,转载必须注明作者和本文链接
六月的风
Junwind
讨论数量: 1

百度的文心一言:

在Go语言中,切片(Slice)的语法s[low:high:max]允许你指定一个切片s的子切片,其中low是子切片开始的位置(包含),high是子切片结束的位置(不包含),而max是一个可选的容量参数,它指定了子切片可以增长到的最大容量,但不影响子切片的初始长度或内容。

然而,需要注意的是,在Go语言的官方文档中,通常只使用s[low:high]这样的语法来创建子切片,其中max(容量)参数是隐式的,它基于原始切片s的容量和low、high的位置自动计算得出。

当你看到s[1:3:6]这样的语法时,它实际上是在说:

  • 从切片s中创建一个新的子切片。
  • 这个子切片从索引1开始(包含索引1的元素)。
  • 这个子切片在索引3结束(不包含索引3的元素)。
  • 这个子切片的最大容量被显式地设置为6,这意味着虽然这个子切片的初始长度是3-1=2(从索引1到索引2的元素),但它可以安全地增长到最多包含6个元素,而不会导致底层数组的重新分配(前提是原始切片s的容量至少为6,并且从索引1开始有足够的空间)。

然而,需要注意的是,max(容量)参数在切片操作中并不常见,因为它通常是由Go语言的运行时自动管理的。在大多数情况下,你只需要关心low和high参数来指定你想要的子切片的部分。

如果你确实需要指定容量(例如,在某些特定的性能优化场景中),你可以使用s[low:high:max]这样的语法,但请确保你了解这样做的原因和后果。

最后,需要强调的是,虽然你可以指定max参数,但如果你尝试向子切片中添加的元素数量超过了其长度和max之间的差值,那么切片仍然会进行扩容操作,这可能会导致底层数组的重新分配。因此,max参数主要是一个性能优化工具,用于在你知道切片将如何增长时减少不必要的内存分配。

1个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
躺平大叔 @ 躺平社区
文章
136
粉丝
15
喜欢
102
收藏
59
排名:274
访问:3.5 万
私信
所有博文
社区赞助商