将引用类型变量“slice”分配给另一个变量时,为什么它们不会同时改变?

huangapple go评论78阅读模式
英文:

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

问题

另一个切片 := theSlice
另一个切片 = append(另一个切片, newEle)
fmt.Println(len(另一个切片) == len(theSlice))

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

以下是其他一些实验:

package main

import "fmt"

func main() {
theSlice := []int{3,3,2,5,12,43}
另一个切片 := theSlice
fmt.Println(另一个切片3, theSlice3)
另一个切片3 = 另一个切片3+2
fmt.Println(另一个切片3, theSlice3)
另一个切片 = append(另一个切片[:3], 另一个切片[4:]...)
fmt.Println(len(另一个切片),len(theSlice))
}

输出结果如下:

5 5
7 7
5 6

程序已退出。

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

This snippet will output false. Why?

And here are some other experiments:

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))
}

The output is like below:

5 5
7 7
5 6

Program exited.

答案1

得分: 2

每当附加的切片anotherSlice没有足够的容量来容纳新元素时,append函数会创建一个新的切片并返回它。从那时起,切片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

英文:

Whenever appended slice anotherSlice has no capacity for the new element, append function creates new slice and returns it. Since then the slices anotherSlice and theSlice are different - they are backed by separate arrays.

Reslicing slice with a shorter length anotherSlice[:3] has no impact on the original capacity of the slice.

The following line:

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

cuts out fourth (index 3) element. Because anotherSlice[:3] has capacity to hold all elements of anotherSlice[4:] no new allocation happens and therefore both slices are modified.

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)
}

<kbd>Playground</kbd>

答案2

得分: 1

为什么一个切片的长度变化不会影响另一个切片的长度变化,与底层存储的复制和/或修改无关。

在Go语言中,重要的是要记住切片是什么。它是一个结构体,包含一个长度字段、一个容量字段和一个指向数组的指针。一些操作会改变长度字段,一些操作会改变容量字段,一些操作会改变底层数组中存储的数据。

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

英文:

The answer to why the length of one slice doesn't follow the change to another slice's length change is not related to the underlying storage potentially being copied and/or modified.

In Go, it is important to remember what a slice is. It is a struct with a length field, a capacity field, and a pointer to an array. Some operations
change the length field. Some change the capacity field. Some change the data stored in the underlying array.

If one doesn't grasp how a slice is implemented in the language, there will be all sorts of confusion and bugs and wasted opportunities. Once one becomes comfortable with how a slice is implemented, they are very easy to use and the fact that the compiler understands the structure of the slice, some very elegant and easily read code can be written.

huangapple
  • 本文由 发表于 2016年4月27日 21:12:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/36890875.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定