如何在不改变原始数组的情况下复制数组?

5

我想复制一个数组,但复制后的数组总是会对原始数组进行更改。为什么会这样呢?

以下是问题的代码示例:

package main

import (
    "fmt"
)

func main() {
    array := make([]int, 2)
    for i := range array {
        array[i] = 0
    }

    oldArray := array
    array[0] = 3 // why does this also change oldArray?
    oldArray[1] = 2 // why does this also change the original array?

    fmt.Println(oldArray, array)
    // I expected [0,2], [3,0]
    // but it returns [3,2], [3,2]

}

我试图在array之前初始化变量oldArray,但结果仍然相同。


2
在大多数编程语言中,当你将一个数组变量赋值给另一个数组变量时,你只是在赋予引用,而不是复制数组的内容。你只是创建了两个指向同一数组的变量。 - Enigmativity
@Enigmativity,非常感谢您提供的信息。因为我通常使用PHP编写代码,并且在JS上也有经验,所以只需要复制内容即可。 - Muhammad Dyas Yaskur
1
array := make([]int, 2) 不会创建一个数组,而是创建了一个切片。 - Jonathan Hall
4
我希望你不要误解,但根据你的标签历史记录,你似乎对Go语言只是“猜测”,可能会给人们留下错误的印象。即使对于数组,Go也是传值而不是传址语言。由于提问者并未使用“数组”,而是使用了一种称为切片的数据类型,因此你的评论无意中是正确的,因为切片本质上是对数组的引用。 - Hymns For Disco
1
@HymnsForDisco - 完全没有冒犯之意。我只是在做一个假设。事实上,我甚至没有对Go做出任何断言。 - Enigmativity
显示剩余8条评论
2个回答

15
在你的示例代码中,你正在使用 slices 而不是 arrays
从切片文档中可以看到:
一个切片是对底层数组连续段的描述,并提供了从该数组中编号顺序访问元素的功能。
当你将一个切片分配给一个变量时,你创建了该描述符的副本,因此处理的是相同的底层数组。当你实际上处理数组时,它具有你所期望的行为。
切片文档中的另一个片段(重点在于我):
一旦初始化,切片总是与持有其元素的底层数组相关联。因此,切片与其数组以及相同数组的其他切片共享存储;相反,不同的数组始终代表不同的存储。
以下是代码示例(对于切片,第一个元素的内存地址用括号括起来,以清楚地指出何时两个切片使用相同的底层数组):
package main

import (
    "fmt"
)

func main() {
    // Arrays
    var array [2]int
    newArray := array
    array[0] = 3
    newArray[1] = 2
    fmt.Printf("Arrays:\narray: %v\nnewArray: %v\n\n", array, newArray)

    // Slices (using copy())
    slice := make([]int, 2)
    newSlice := make([]int, len(slice))
    copy(newSlice, slice)
    slice[0] = 3
    newSlice[1] = 2
    fmt.Printf("Slices (different arrays):\nslice (%p): %v \nnewSlice (%p): %v\n\n", slice, slice, newSlice, newSlice)

    // Slices (same underlying array)
    slice2 := make([]int, 2)
    newSlice2 := slice2
    slice2[0] = 3
    newSlice2[1] = 2
    fmt.Printf("Slices (same array):\nslice2 (%p): %v \nnewSlice2 (%p): %v\n\n", slice2, slice2, newSlice2, newSlice2)
}

输出:

Arrays:
array: [3 0]
newArray: [0 2]

Slices (different arrays):
slice (0xc000100040): [3 0] 
newSlice (0xc000100050): [0 2]

Slices (same array):
slice2 (0xc000100080): [3 2] 
newSlice2 (0xc000100080): [3 2]

Go Playground

意思是“Go 游乐场”,它是一个在线的 Go 语言编程环境,可以让用户在浏览器中编写、运行和分享 Go 代码。

1
对于初学者来说,阅读到这里可能会更加微妙:https://play.golang.org/p/kbVvThLjaGf - user4466350

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接