Go – How to preallocate and fill a slice of pointers in a go-idiomatic way

goslice

http://play.golang.org/p/j-Y0mQzTdP

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]*UselessStruct, 5)
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, &UselessStruct{})
    }

    fmt.Println(mySlice)
}

Outputs: [<nil> <nil> <nil> <nil> <nil> 0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0]

What i would like to do, is preallocate memory for 5 UselessStructs, stored as pointers. If i declare a slice of struct values eq:

mySlice := make([]UselessStruct, 5)

then this creates 5 empty structs – appending doesn't replace the empty structs, but rather keeps on adding to the slice, so the end result with this code:

http://play.golang.org/p/zBYqGVO85h

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]UselessStruct, 5)
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, UselessStruct{})
    }

    fmt.Println(mySlice)
}

is: [{0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0}]

What is the the go-idiomatic way to preallocate and fill slices?

Best Answer

For your first example, I would do:

mySlice := make([]*UselessStruct, 5)
for i := range mySlice {
     mySlice[i] = new(UselessStruct)
}

The issue you are facing in both examples is you are appending to a slice that is already the correct length. If you set mySlice := make([]*UselessStruct, 5), you are asking for a slice of nil pointers of length 5. If you append one pointer, it now has length 6.

Instead, you want to use mySlice := make([]*UselessStruct, 0, 5). This creates a slice of length 0 but capacity 5. Each time you append it will add one to the length but it won't reallocate until you exceed the slice's capacity.

mySlice := make([]*UselessStruct, 0, 5)
for i := 0; i != 5; i++ {
    mySlice = append(mySlice, &UselessStruct{})
}
// mySlice is [0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0]

Both of my examples will work as you expect but I recommend the first one for purely style reasons.

Related Topic