Copying arrays to slices in Go

Viewed 156

Please can you help me understand how generating a slice from an array works. Why are ID1 and ID2 not the same?

    a := [2]string{"a", "b"}
    b := [2]string{"c", "d"}
    var z [2][2]string
    z[0] = a
    z[1] = b

    fmt.Printf("%s\n", z)
    var id [][]string
    for _, t := range z {
        temp := t[:]
        id = append(id, temp)
    }
    fmt.Printf("\nid1 = %s", id)

    var id2 [][]string
    for _, t := range z {
        temp := t
        id2 = append(id2, temp[:])
    }
    fmt.Printf("\nid2 = %s", id2)

[[a b] [c d]]

id1 = [[c d] [c d]]
id2 = [[a b] [c d]]

3 Answers

Because the for range loop has a single iteration variable which is reused in each iteration. Spec: For statements: For statements with for clause

Variables declared by the init statement are re-used in each iteration.

So in your first loop:

for _, t := range z {
    temp := t[:]
    id = append(id, temp)
}

There is a single t, and you slice the same t array, so each temp slice you append, it will point to the same backing array, which is t, and it is overwritten in each iteration, so its value will be the value of the last iteration: [c d].

In your second loop:

for _, t := range z {
    temp := t
    id2 = append(id2, temp[:])
}

Also there is a single t iteration variable, but you make a copy of it: temp := t, and you slice this copy, which is detached from t, and you append a slice that has the copy as its backing array, which will not be overwritten in each iteration.

This is the problematic assignment. It is not what it seems:

temp := t[:]

Here, t is an array and the loop variable. That means at each iteration, the contents of the current array is copied onto t. At the first iteration, t=[]string{"a","b"}, and a slice is created to point to this array and assigned to temp. At the second iteration t is overwritten to become []string{"c","d"}. This operation also overwrites the contents of the first slice. So, you end up with the {{"c","d"},{"c","d"}}. The important point here is that contents of t gets overwritten, and t is shared between the two slices.

In the first loop you are saving slices which have the same backing array (ie. the loop variable t). In the second loop you are storing slices using different backing arrays since you make a copy of t in temp.

Related