golang:切片扩容和随之带来的“坑”

golang中的slice是引用类型,比如下面这段代码:

    s1 := []int{1,2,3,4}

    s2 := s1

    s1[0] = 100

    fmt.Printf("s1=%v,s2=%v", s1, s2)

会看到s1和s2都变成了[100 2 3 4],因为它们共享同一个内存地址。

然而......

我们来看看下面这个“坑”

    s1 := []int{1,2,3,4}

    s2 := s1

    s1 = append(s1, 5)

    s3 := s1

    s1 = append(s1, 6) 

    s1[0] = 100

    fmt.Printf("s1=%v,s2=%v,s3=%v", s1, s2, s3)

返回结果是:s1=[100 2 3 4 5 6], s2=[1 2 3 4], s3=[100 2 3 4 5]  按理说引用传值,s2的第一个元素也应该是100

要解释这个问题,就要谈一下golang中slice的扩容机制。当切片的长度超出cap容量的时候,就会引发切片扩容,每次增加一倍的容量(当容量达到1024以后,每次增加的量大约是之前的25%~35%)。经扩容后的切片会复制到新的内存地址中

所以在上面的例子中,当s1第一次append时,触发扩容,cap(s1)从4变到8,此时s1和s2已经不是同一个内存地址了。而当s1第二次append时,cap(s1)依旧是8,没有发生扩容,所以s1和s3是同一个内存地址。最终s3的元素跟随s1变动,而s2没有。

你可能感兴趣的:(golang:切片扩容和随之带来的“坑”)