Append Go Slice Change Other Slice Value
Array in go doesn’t like array in other language. The array’s size is fixed and cannot be changed. Dynamic sized array in go is slice. The basic info of array and slice can be found in here. Appending new element in slice is allowed and the size will be increased if required. But appending slice may cause other slice’s element changed.
Example
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3}
slice2 := append(slice1, 4)
fmt.Println("slice2", slice2)
slice3 := append(slice2, 5)
fmt.Println("slice3", slice3) // [1 2 3 4 5]
slice4 := append(slice2, 6)
fmt.Println("slice4", slice4) // [1 2 3 4 6]
fmt.Println("slice3", slice3) // [1 2 3 4 6]
}
Go Playground link: https://go.dev/play/p/MHltdaxLziE
Graph
Explanation
The design of slice is array with capacity length and using length to restrict the element can be accessed in slice. In line 6, slice1
is declared with [3]int
to store the three element.
And then in line 7, element 4
is appended into slice1
which will exceed the 3 elements limit in array. So go runtime will create another array with double size ([6]int
) and append 4
to the array to create slice2
. At this moment, the array size is 6 which means the pointer for fifth and sixth element is already exist.
In line 9, element 5
is append into array of slice2
which is using the fifth pointer in array and become slice3
.
In line 11, element 6
is append into array of slice2
which is using the fifth pointer in array and become slice4
.
So in line 9 and line 11, they are updating the same pointer in same array. So in the append function in line 11 will update the slice3
even not using slice3
in the function.
Workaround
Using copy function to make a new slice.
The copy function here is copying the value of slice2
to slice3
. So the pointers in slice3
array are differ from slice2
now.
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3}
slice2 := append(slice1, 4)
fmt.Println(slice2)
slice3 := make([]int, len(slice2))
copy(slice3, slice2)
slice3 = append(slice3, 5)
fmt.Println("slice3", slice3) // [1 2 3 4 5]
slice4 := append(slice2, 6)
fmt.Println("slice4", slice4) // [1 2 3 4 6]
fmt.Println("slice3", slice3) // [1 2 3 4 5]
}
Go Playground link: https://go.dev/play/p/sPbG-dsiT9x