问一个关于切片和数组的问题。

2021-07-21 15:25:00 +08:00
 jenrey
package main

import "fmt"

func main() {
	x1 := [...]int{1, 3, 5} // 数组
	s1 := x1[:]             // 切片
	// s1=[1 3 5],len(s1)=3,cap(s1)=3,0xc0000b6000
	fmt.Printf("s1=%v,len(s1)=%v,cap(s1)=%v,%p\n", s1, len(s1), cap(s1), s1)
	/*
		1 、切片不保存具体的值
		2 、切片对应一个底层数组
		3 、底层数组都是占用一块连续的内存
	*/
	s1 = append(s1[:1], s1[2:]...) // 相当于改的是底层数组!!!
	// s1=[1 5],len(s1)=2,cap(s1)=3,0xc0000b6000
	fmt.Printf("s1=%v,len(s1)=%v,cap(s1)=%v,%p\n", s1, len(s1), cap(s1), s1)
	fmt.Println(x1) // [1 5 5]
}

因为 Go 没有删除切片元素的专用方法,那么切片append的时候,实际是删除了索引为 1 的元素 3,所以切片打印为[1 5]

但是为什么数组最后是[1 5 5]呢?

个人猜测:
因为数组初始化后长度是固定的,不可变更。
所以,切片把数组的索引为 1 的元素 3删除了,进而把元素 5放在了元素 3的索引处,导致数组的值变成了[1 5 5],而数组索引为 2 的元素 5的值及内存地址是没变化的(我比较了 &s1[2] 和 &x1[2] 发现是一样的)。

希望各位 Go 前辈解惑。万分感谢您的回复。

1125 次点击
所在节点    Go 编程语言
3 条回复
hahasong
2021-07-21 15:47:31 +08:00
append 的行为是不确定的,数组装的下就在原数组上装,装不下就给你生成新数组了
pabupa
2021-07-21 15:51:36 +08:00
没有删除,slice 只会在空间不够时,重新申请一份更大的,复制过去。然后释放原来数组的引用,而要不要删掉原来的数组是 gc 的事情。
jim9606
2021-07-21 15:56:19 +08:00
这个猜测没什么问题。
如果 s1 的 append 触发了扩容,追加元素前会对 s1 进行一次 copy,那么 x1 的值就不会变,这里因为没有触发扩容所以影响到 x1 了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/790847

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX