Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capacity of slices in Go

Tags:

slice

append

go

I have a question about the below code

package main

import "fmt"

func main() {
    var a []int
    printSlice("a", a)

    // append works on nil slices.
    a = append(a, 0)
    printSlice("a", a)

    // the slice grows as needed.
    a = append(a, 1)
    printSlice("a", a)

    // we can add more than one element at a time.
    a = append(a, 2, 3, 4)
    printSlice("a", a)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
    s, len(x), cap(x), x)
}       

I always guess what the result of running a piece of code will look like then run the code and check if my guess is correct. But this code resulted a little bit different from my guess:

Result:
On my local go tour server:

a len=0 cap=0 []
a len=1 cap=1 [0]
a len=2 cap=2 [0 1]
a len=5 cap=6 [0 1 2 3 4]      

Everything is ok until the last line but I don't get

cap=6     

why not

cap=5    

My opinion is I did not create slice with explicit capacity therefore my system gave it this value of 6.

2) But when I tried this same code on the golang tour server I get a little more diffferent result like this :

a len=0 cap=0 []
a len=1 cap=2 [0]
a len=2 cap=2 [0 1]
a len=5 cap=8 [0 1 2 3 4]   

What about cap=2 on the second line and cap=8 on the last line?

like image 583
Maksat Yalkabov Avatar asked Jul 25 '16 17:07

Maksat Yalkabov


Video Answer


1 Answers

This question isn't an exact duplicate, but my answer here also effectively answers this.

TL;DR — how much the capacity of the slice is expanded by isn't mentioned in the specification and different versions of Go (or different implementations, or the same version on different architectures, etc.) can expand the slice by different amounts.

The reason you might want to make the capacity larger than you need is because underneath the slice there is an array which is immutable (it can't be expanded). When you "grow" a slice what actually happens is that you make a new (longer) array, copy all the values over, and then set that as the backing array for the slice. If you were appending lots of values, you'd have to do lots and lots of copies (one for every single value), which would be very slow, so instead the runtime allocates more space than it thinks you need so that it has to make copies less often.

like image 63
Sam Whited Avatar answered Oct 22 '22 14:10

Sam Whited