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