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?
Using make() function: You can also create a slice using the make() function which is provided by the go library. This function takes three parameters, i.e, type, length, and capacity. Here, capacity value is optional.
Slices are pointers to arrays, with the length of the segment, and its capacity. They behave as pointers, and assigning their value to another slice, will assign the memory address.
Golang make() is a built-in slice function used to create a slice. The make() function takes three arguments: type, length, and capacity, and returns the slice. To create dynamically sized arrays, use the make() function. The make() function allocates a zeroed array and returns a slice that refers to that array.
A struct is just often more useful in Go, since the fields and their types are statically known, as well as being more efficient, since fields are stored directly and at known offsets which don't need to be computed on each access.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With