5

I want to copy an array but the copied array always makes changes to the original array as well. Why is this the case?

Below is a code example of the issue:

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]

}

I tried to initiate the variable oldArray before array but the result is the same.

Shaido
  • 27,497
  • 23
  • 70
  • 73
Muhammad Dyas Yaskur
  • 6,914
  • 10
  • 48
  • 73
  • 2
    In most languages when you assign one array variable to another you're just assigning the reference and you're NOT copying the contents of the array. You're just making two variables that point to the same array. – Enigmativity Mar 11 '21 at 05:41
  • @Enigmativity , Thank you very much for your information. Because usually I write in PHP and as I remembered on JS too, will just copying content. – Muhammad Dyas Yaskur Mar 11 '21 at 05:45
  • 1
    `array := make([]int, 2)` does not create an array. It creates a slice. – Jonathan Hall Mar 11 '21 at 07:07
  • @Flimzy yes, my bad didn't know what is slice, because I'm just learning Go by convert my existing PHP to Go. – Muhammad Dyas Yaskur Mar 11 '21 at 08:51
  • 4
    @Enigmativity I hope this isn't taken as an offense, but it seems that you're "guessing" about Go (based on your tag history) and probably giving people the wrong idea. Go is a pass-by-copy language, even for arrays. Your comment is incidentally true because the asker is not using "arrays", but a data type called a slice, which by definition is a reference to an array. – Hymns For Disco Mar 11 '21 at 08:58
  • 1
    @HymnsForDisco - No offence taken whatsoever. I was making an assumption. Indeed I didn't even make an assertion about Go. – Enigmativity Mar 11 '21 at 11:19
  • Does this answer your question? [Function for copying arrays in Go language](https://stackoverflow.com/questions/18559830/function-for-copying-arrays-in-go-language) – Peter Duniho Mar 12 '21 at 01:40
  • I don't know much about Go, but based on the proposed duplicate, and especially [this answer](https://stackoverflow.com/a/18560166), it looks to me as though simple assignment performs a _copy_ of the contents of an array object. In any case, the proposed duplicate provides a number of options for making a copy of an array that can be mutated without mutating the original. – Peter Duniho Mar 12 '21 at 01:42
  • See also [this answer](https://stackoverflow.com/a/21722697) in [Passing an array as an argument in golang](https://stackoverflow.com/questions/21719769/passing-an-array-as-an-argument-in-golang) – Peter Duniho Mar 12 '21 at 01:44
  • See also [this answer](https://stackoverflow.com/a/38645895) in [Why have arrays in Go?](https://stackoverflow.com/questions/38645175/why-have-arrays-in-go) – Peter Duniho Mar 12 '21 at 01:46
  • See also [this answer](https://stackoverflow.com/a/41887304) in [GO - Is array copy a deep copy or shallow copy?](https://stackoverflow.com/questions/41887050/go-is-array-copy-a-deep-copy-or-shallow-copy) – Peter Duniho Mar 12 '21 at 01:47
  • See also [this answer](https://stackoverflow.com/a/26433284) in [Generic way to duplicate slices](https://stackoverflow.com/questions/26433156/generic-way-to-duplicate-slices) – Peter Duniho Mar 12 '21 at 01:48
  • See also [this answer](https://stackoverflow.com/a/4221820) in [Treatment of Arrays in Go](https://stackoverflow.com/questions/4221698/treatment-of-arrays-in-go) – Peter Duniho Mar 12 '21 at 01:50

2 Answers2

15

In your example code, you're working with slices, not arrays.

From the slice documentation:

A slice is a descriptor for a contiguous segment of an underlying array and provides access to a numbered sequence of elements from that array.

When you assign a slice to a variable, you're creating a copy of that descriptor and therefore dealing with the same underlying array. When you're actually working with arrays, it has the behavior you're expecting.

Another snippet from the slice documentation (emphasis mine):

A slice, once initialized, is always associated with an underlying array that holds its elements. A slice therefore shares storage with its array and with other slices of the same array; by contrast, distinct arrays always represent distinct storage.

Here's a code sample (for the slices, the memory address of the first element is in parentheses, to clearly point out when two slices are using the same underlying array):

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

Output:

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

chuckx
  • 6,484
  • 1
  • 22
  • 23
  • 1
    to a beginner reading that far, It might also get more subtle: https://play.golang.org/p/kbVvThLjaGf –  Mar 11 '21 at 23:01
4

use copy function.

oldArray := make([]int, len(array))
copy(oldArray, array)

https://play.golang.org/p/DsLJ2PDIy_N

Jeffy Mathew
  • 570
  • 4
  • 16