V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
jenrey
V2EX  ›  Go 编程语言

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

  •  
  •   jenrey · 2021-07-21 15:25:00 +08:00 · 1223 次点击
    这是一个创建于 1224 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 前辈解惑。万分感谢您的回复。

    3 条回复    2021-07-21 15:56:19 +08:00
    hahasong
        1
    hahasong  
       2021-07-21 15:47:31 +08:00
    append 的行为是不确定的,数组装的下就在原数组上装,装不下就给你生成新数组了
    pabupa
        2
    pabupa  
       2021-07-21 15:51:36 +08:00
    没有删除,slice 只会在空间不够时,重新申请一份更大的,复制过去。然后释放原来数组的引用,而要不要删掉原来的数组是 gc 的事情。
    jim9606
        3
    jim9606  
       2021-07-21 15:56:19 +08:00
    这个猜测没什么问题。
    如果 s1 的 append 触发了扩容,追加元素前会对 s1 进行一次 copy,那么 x1 的值就不会变,这里因为没有触发扩容所以影响到 x1 了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5985 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:44 · PVG 10:44 · LAX 18:44 · JFK 21:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.