切片的疑问?
直接看代码
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 协议》,转载必须注明作者和本文链接
百度的文心一言:
在Go语言中,切片(Slice)的语法s[low:high:max]允许你指定一个切片s的子切片,其中low是子切片开始的位置(包含),high是子切片结束的位置(不包含),而max是一个可选的容量参数,它指定了子切片可以增长到的最大容量,但不影响子切片的初始长度或内容。
然而,需要注意的是,在Go语言的官方文档中,通常只使用s[low:high]这样的语法来创建子切片,其中max(容量)参数是隐式的,它基于原始切片s的容量和low、high的位置自动计算得出。
当你看到s[1:3:6]这样的语法时,它实际上是在说:
然而,需要注意的是,max(容量)参数在切片操作中并不常见,因为它通常是由Go语言的运行时自动管理的。在大多数情况下,你只需要关心low和high参数来指定你想要的子切片的部分。
如果你确实需要指定容量(例如,在某些特定的性能优化场景中),你可以使用s[low:high:max]这样的语法,但请确保你了解这样做的原因和后果。
最后,需要强调的是,虽然你可以指定max参数,但如果你尝试向子切片中添加的元素数量超过了其长度和max之间的差值,那么切片仍然会进行扩容操作,这可能会导致底层数组的重新分配。因此,max参数主要是一个性能优化工具,用于在你知道切片将如何增长时减少不必要的内存分配。