切片复制会改变原始切片。

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

Slice copy mutating original slice

问题

有人可以帮忙解释一下为什么这段代码会改变原始数组 a 的 Golang 内部机制吗?

func main() {
	a := []int{1,2,3,4}
	b := a
	b = append(b[0:1], b[2:]...)
	fmt.Println(b)
	fmt.Println(a)
}

输出结果:

[1 3 4]
[1 3 4 4]

我原以为 b := a 是按值传递的。提前谢谢。

英文:

Could someone help explain the Golang internals of why this code is mutating the original array a?

func main() {
	a := []int{1,2,3,4}
	b := a
	b = append(b[0:1], b[2:]...)
	fmt.Println(b)
	fmt.Println(a)
}

Output:

[1 3 4]
[1 3 4 4]

I thought b := a would be passing by value. Thanks in advance.

答案1

得分: 5

这就是切片的工作原理。切片只是一个指针(加上大小和容量),实际的数据存储在数组中。

当你复制一个切片时,底层数组并没有被复制。这样你就得到了两个指向同一个数组的切片。通过一个切片修改值会通过另一个切片可见。

详细信息请参见Go切片:用法和内部原理

如果你想保留原始切片不变,首先进行深拷贝。例如像这样:

b := append([]int{}, a...)  // 深拷贝

在线演示

英文:

That's how slices work. A slice is just a pointer(+size+capacity), the actual data is stored in the array.

When you copy a slice, the underlying array is not copied. Then you end up with two slices pointing to the same array. Mutating the values of one slice will become visible via the other slice.

See Go Slices: usage and internals for more details.

If you want to leave the original slice untouched, first make a deep copy. For example like this

    b := append([]int{}, a...)  // deep copy

(Live demo)

答案2

得分: 1

切片基本上是对数组的包装。切片本身没有数据,它们只是持有对数组的引用。在你给出的代码中,你将a赋值给了b,现在它们都指向同一个数组。所以当你修改切片b时,切片a也会被修改。

你可以使用copy方法将一个数组的元素复制到另一个数组中。

// copy返回复制的元素总数
count := copy(b /*目标数组*/ , a /*源数组*/)

但是请确保分配一个与源数组长度相同的数组。
以下是一个示例:

func main() {
    a := []int{1,2,3,4}
    b := make([]int, len(a))

    _ = copy(b, a)

    a[0] = 2

    fmt.Println(b)
    fmt.Println(a)
}
英文:

Slices are basically wrapper over arrays. Slices doesn't have their own data they just hold the reference to the arrays. In your given code you are assigning a to b now they both are indicating the same array. And so when you are mutating the slice b the slice a is also being mutated.

You can use copy method to copy elements from one array to another.

// copy returns the count of total copied elements
count := copy(b /*destination*/ , a /*source*/)

But make sure to allocate an array with the same length of source array.
Example is given below:

func main() {
    a := []int{1,2,3,4}
    b := make([]int, len(a))

    _ = copy(b, a)

    a[0] = 2

    fmt.Println(b)
    fmt.Println(a)
}

huangapple
  • 本文由 发表于 2021年8月29日 00:41:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/68966356.html
匿名

发表评论

匿名网友

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

确定