Append to slice
suggest changeBuilt-in function append(slice, elements...)
adds element to a slice and returns a new slice.
Append a single value
a := []string{"hello"}
a = append(a, "world")
fmt.Printf("a: %#v\n", a)
a: []string{"hello", "world"}
Append multiple values
a := []string{"hello"}
a = append(a, "world", "now")
fmt.Printf("a: %#v\n", a)
a: []string{"hello", "world", "now"}
Append a slice to a slice
a := []string{"!"}
a2 := []string{"Hello", "world"}
a = append(a, a2...)
fmt.Printf("a: %#v\n", a)
a: []string{"!", "Hello", "world"}
Append might create a new slice
Maybe you noticed the pattern a = append(a, ....)
.
A slice uses an array of fixed size for storage. When number of slice elements exceeds size of array, append
needs to re-allocate the array and create a new slice. For efficiency the newly allocated array has some spare elements, so that we don't have to re-allocate backing array every time we append an element to a slice.
This program shows how many elements it takes to re-allocate new array.
var a []int
ptr := fmt.Sprintf("%p", a)
n := 0
nAppends := 0
for {
a = append(a, 1)
nAppends++
currPtr := fmt.Sprintf("%p", a)
if currPtr != ptr {
fmt.Printf("Appends needed to re-allocate slice: %d\n", nAppends)
nAppends = 0
ptr = currPtr
n++
if n == 6 {
break
}
}
}
Appends needed to re-allocate slice: 1
Appends needed to re-allocate slice: 1
Appends needed to re-allocate slice: 1
Appends needed to re-allocate slice: 2
Appends needed to re-allocate slice: 4
Appends needed to re-allocate slice: 8
As you can see, the number of appends needed to re-create the array increases with the size of the slice.
Go doesn't allow comparing slices so we use the fact that in current implementation we can take address of the slice (%p
) and that address can be used as identity of slice.
This is an internal implementation detail that might change in the future.