This question already has an answer here:
Running the example The Go Tour on server (currently on version 1.12.7), I find the capacity of slice doubling to the next power of 2, if the new slice length is larger than current backing array's length.
If I run the same program on my machine (version 1.10.3 on windows), the slice capacity changes to next multiple of two.
Why are they different? Is it because of Go version or run-time implementations? Is the capacity change deterministic?
The output on remote server is this
len=0 cap=0 []
len=1 cap=2 [0]
len=2 cap=2 [0 1]
len=5 cap=8 [0 1 2 3 4]
The output on local machine is this
len=0 cap=0 []
len=1 cap=1 [0]
len=2 cap=2 [0 1]
len=5 cap=6 [0 1 2 3 4]
This is the code for reference
package main
import "fmt"
func main() {
var s []int
printSlice(s)
// append works on nil slices.
s = append(s, 0)
printSlice(s)
// The slice grows as needed.
s = append(s, 1)
printSlice(s)
// We can add more than one element at a time.
s = append(s, 2, 3, 4)
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v
", len(s), cap(s), s)
}
</div>
TL;DR: It depends on the size of the elements stored in the array
The implementation can be seen here:
https://github.com/golang/go/blob/master/src/runtime/slice.go
But as you can see looking into the history it can't be relied to stay the same over time.
That might also explain the difference you may note on different versions of Go.
Making some tests show how a 0-size struct will increment capacity by just 1 element, and int or string will duplicate on each growth, and a 3-byte struct "roughly" doubles on each growth.
You can execute code like this using different types to see these different cases in action:
arr := []struct{}{}
oldCap := 0
for i := 0; i < 100; i++ {
arr = append(arr, struct{}{})
if cap(arr) != oldCap {
oldCap = cap(arr)
fmt.Println("arr", cap(arr))
}
}
Playground showing the cases described above:
According to information from Go slice internal The implementation behaviour of append is as follows.
It is just a multiple of the (len(source slice) + len(new data)) * 2
func AppendByte(slice []byte, data ...byte) []byte {
m := len(slice)
n := m + len(data)
if n > cap(slice) { // if necessary, reallocate
// allocate double what's needed, for future growth.
newSlice := make([]byte, (n+1)*2)
copy(newSlice, slice)
slice = newSlice
}
slice = slice[0:n]
copy(slice[m:n], data)
return slice
}