将一个引用类型"slice"的变量赋值给另一个变量,为什么它们不同时变化?

Assigning a variable of reference type "slice" to another variable, why don't they change simultaneously?

anotherSlice := theSlice
anotherSlice = append(anotherSlice, newEle)
fmt.Println(len(anotherSlice) == len(theSlice))

此代码段将输出 false。为什么?

还有一些其他的实验:

package main

import "fmt"

func main() {
    theSlice := []int{3,3,2,5,12,43}
    anotherSlice := theSlice
    fmt.Println(anotherSlice[3], theSlice[3])
    anotherSlice[3] = anotherSlice[3]+2
    fmt.Println(anotherSlice[3], theSlice[3])
    anotherSlice = append(anotherSlice[:3], anotherSlice[4:]...)
    fmt.Println(len(anotherSlice),len(theSlice))
}

输出如下:

5 5
7 7
5 6

Program exited.

只要附加的切片 anotherSlice 没有新元素的容量,append 函数就会创建新的切片并 returns 它。从那时起,切片 anotherSlicetheSlice 就不同了——它们由不同的数组支持。

重新分割长度较短的切片anotherSlice[:3]对切片的原始容量没有影响。

下面一行:

anotherSlice = append(anotherSlice[:3], anotherSlice[4:]...)

删除第四个(索引 3)元素。因为 anotherSlice[:3] 有能力容纳 anotherSlice[4:] 的所有元素,所以没有新的分配发生,因此两个切片都被修改了。

package main

import (
        "fmt"
)   

func main() {
        x := []int{1, 2, 3, 4, 5, 6}
        fmt.Println(cap(x[:3]) >= len(x[:3])+len(x[4:]))
        y := append(x[:3], x[4:]...)
        fmt.Println(x, y)
}

Playground

为什么一个切片的长度不跟随另一个切片的长度变化的答案与潜在被复制and/or修改的底层存储无关。

在 Go 中,记住切片是什么很重要。它是一个具有长度字段、容量字段和指向数组的指针的结构。一些操作 更改长度字段。一些更改容量字段。有些更改存储在底层数组中的数据。

如果不了解切片是如何在语言中实现的,就会出现各种混乱、错误和浪费的机会。一旦熟悉了切片的实现方式,它们就非常易于使用,而且编译器理解切片的结构这一事实,可以编写一些非常优雅且易于阅读的代码。