关于golang slice切片的一个问题

slice[i:j:k]其中 i 表示从 slice 的第几个元素开始切,j 控制切片的长度(j-i),k 控制切片的容量(k-i),如果没有给定 k,则表示切到底层数组的最尾部。

注意: k控制切片的容量,不是说k的值是多少就是cap是多少,cap=k-i

func testCapNotEnough() {
	slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	cut := slice[1:3:3]
	fmt.Println("before slice:", slice)
	fmt.Println("before cut:", cut)
	fmt.Println("before cut's cap:", cap(cut))

	cut[0] = 9
	cut = append(cut, 99)

	fmt.Println("after slice:", slice)
	fmt.Println("after cut:", cut)
	fmt.Println("after cut's cap:", cap(cut))
}
**output:**
before slice: [1 2 3 4 5 6 7 8 9 10]
before cut: [2 3]
before cut's cap: 2
after slice: [1 9 3 4 5 6 7 8 9 10]
after cut: [9 3 99]
after cut's cap: 4

再看下面的代码:

func testCapEnough() {
	slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	cut := slice[1:3:4]
	fmt.Println("before slice:", slice)
	fmt.Println("before cut:", cut)
	fmt.Println("before cut's cap:", cap(cut))

	cut[0] = 9
	cut = append(cut, 99)

	fmt.Println("after slice:", slice)
	fmt.Println("after cut:", cut)
	fmt.Println("after cut's cap:", cap(cut))
}
**output:**
before slice: [1 2 3 4 5 6 7 8 9 10]
before cut: [2 3]
before cut's cap: 3
after slice: [1 9 3 99 5 6 7 8 9 10]
after cut: [9 3 99]
after cut's cap: 3

为什么只有一个一行代码的差距,结果差距这么大
cut := slice[1:3:3]
cut := slice[1:3:4]
不仅源slice结果都不一样,cut结果也不一样
cut := slice[1:3:3] 表示cut的容量cap=3-1,而切片从slice上也是切下[1:3]两个元素,也就是如果这时候如果append一个元素99到cut,cut切片的容量是不够的,只能重新开辟一片内存,将数据拷贝过去,然后再将新增的元素99加到末尾,所以这时候的cut和slice已经不是同一个内存了。这就解释了为什么testCapNotEnough()里append之后,slice里没有99这个值,另外append之前cut的cap是2,而元素数量也是2,所以append需要需要扩容将cap翻倍,也就是2翻一倍,所以append之后cut的cap是4。

再看看testCapEnough(), cut := slice[1:3:4],从slice上也是切下[1:3]两个元素,但是切片的时候,cut的容量cap为4-1=3,也就是说这时候cut的容量还没有满,还能再append一个元素,同时内存空间还是跟slice共用同一个,所以append一个99进去的时候,slice和cut两个切片都会有变化。

posted @ 2021-10-08 16:11  werbenhu  阅读(71)  评论(0编辑  收藏  举报