How to copy array without changing original array?

Viewed 1330

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.

2 Answers

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

Related