0

For

package main

import "fmt"

func main() {


    b := make([]int, 1, 5)  
    printSlice("b", b[:cap(b)])
    
    b2 := append(b, 1)
    b3 := append(b2, 1)
    b4 := append(b3, 1)
    b5 := append(b4, 1)
    
    printSlice("bbbb", b5[:cap(b5)])
    
    b6 := append(b5, 1)
    
    printSlice("bbbb", b6[:cap(b6)])
    
    
}

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

The results is

b len=5 cap=5 [0 0 0 0 0]
bbbb len=5 cap=5 [0 1 1 1 1]
bbbb len=10 cap=10 [0 1 1 1 1 1 0 0 0 0]

It looks like the last append double the underlying array size, is there a way to say make it as size 6?

icza
  • 389,944
  • 63
  • 907
  • 827
william007
  • 17,375
  • 25
  • 118
  • 194

2 Answers2

5

You can't control the result capacity if you're using the builtin append(). It doesn't document the capacity growth strategy, so there's nothing to expect (except that the elements being appended will fit into it). It usually allocates more than needed, thinking of future growth (to reduce future allocations). Spec: Appending to and copying slices lists all "guarantees" you have reguarding append() and the resulting slice's capacity:

If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.

If you want to control the resulting slice's capacity, you have to allocate it yourself, copy over the old slice and append to the new, e.g.:

b6 := make([]int, len(b5), len(b5)+1)
copy(b6, b5)
b6 = append(b6, 1)

Then output will be (try it on the Go Playground):

b len=5 cap=5 [0 0 0 0 0]
bbbb len=5 cap=5 [0 1 1 1 1]
bbbb len=6 cap=6 [0 1 1 1 1 1]

As you can see, there's a "lot" that needs to be done: new slice to be created (with backing array), old copied over, and then the append operation (this could be optimized by creating the new slice like make([]int, len(b5)+1), then the final append is just b6[len(b6-1] = 1). It would be a waste to do these all the time when a single element is appended, that's why append() allocates more so this doesn't have to executed all the time.

See related questions:

Go slices - capacity/length?

Golang slice append vs assign performance

Insert a value in a slice at a given index

Concatenate two slices in Go

icza
  • 389,944
  • 63
  • 907
  • 827
3

is there a way to say make it as size 6?

No. Append does what it does. But nothing stops you from providing a slice with the desired cap.

Volker
  • 40,468
  • 7
  • 81
  • 87