我的代码片段
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
fmt.Println("check 1: ",s, len(s))
s = s[1:4]
fmt.Println("check 2: ",s, len(s))
s = s[3:5]
fmt.Println("check 3: ",s, len(s))
s = s[1:]
fmt.Println("check 4: ",s, len(s))
}
输出
check 1: [2 3 5 7 11 13] 6
check 2: [3 5 7] 3
check 3: [11 13] 2
check 4: [13] 1
我的预期产出
check 1: [2 3 5 7 11 13] 6
check 2: [3 5 7] 3
panic: runtime error: slice bounds out of range [3:5]
s = s[1:4]
- 这里我们更新了切片变量 s,它现在包含 [3 5 7] 并且 s = s[3:5]
应该给出 out of range error
,因为索引 3 到 5 不存在于 s 的新值中
相反,为什么输出打印 - [11 13]
当切片容量大于切片长度时,可能会造成一些混乱。关键思想是切片是数组的视图。您无法访问超出切片边界的内容,但您可以重新切片并获得底层数组的新视图。
最初,切片长度和容量为 6。
s = s[1:4]
之后,切片长度为3,容量为5。您可以将此切片重新切片到大于3个元素,并且仍然访问底层数组的元素。
因此,
s[3:5]
是有效的,并且相当于原始切片的[4:6]
。
这是根据 golangs 切片规则。 Golangs slice 的工作方式与其他语言略有不同。当从切片或数组中取出切片时,它指向前一个数组或切片而不是复制。
{2,3, 5, 7, 11, 13} //length 6
s = s[1:4] //length 3 but it points here ^ and ends here ^
{2,3, 5, 7, 11, 13}
s = s[3:5] // it points here ^ and ends here ^
所以如果你这样做了
s = s[3:6]
它会因索引超出边界而恐慌。
正如 golang 文档中提到的 - 切片不存储任何数据,它只是描述底层数组的一部分。 切片同时具有长度和容量。 切片的长度是它包含的元素数量。 切片的容量是基础数组中的元素数量,从切片中的第一个元素开始计数。 切片 s 的长度和容量可以使用表达式 len(s) 和 cap(s) 获得。
虽然执行 s[1:4]
后长度为
3,但容量为 5,因此您可以从底层数组访问 s[3:5] 而不会出现索引输出错误
尝试以下代码片段以更好地理解
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
fmt.Printf("check 1: len=%d cap=%d %v\n", len(s), cap(s), s)
s = s[1:4]
fmt.Printf("check 2: len=%d cap=%d %v\n", len(s), cap(s), s)
s = s[3:5]
fmt.Printf("check 4: len=%d cap=%d %v\n", len(s), cap(s), s)
s = s[1:]
fmt.Printf("check 5: len=%d cap=%d %v\n", len(s), cap(s), s)
}
输出:
check 1: len=6 cap=6 [2 3 5 7 11 13]
check 2: len=3 cap=5 [3 5 7]
check 4: len=2 cap=2 [11 13]
check 5: len=1 cap=1 [13]