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

Go Slice

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