14

I'm wondering about best practices when initializing empty arrays.

i.e. Is there any difference here between arr1, arr2, and arr3?

myArr1 := []int{}
myArr2 := make([]int,0)
var myArr3 []int

I know that they make empty []int but I wonder, is one syntax preferable to the others? Personally I find the first to be most readable but that's beside the point here. One key point of contention may be the array capacity, presumably the default capacity is the same between the three as it is unspecified. Is declaring arrays of unspecified capacity "bad"? I can assume it comes with some performance cost but how "bad" is it really?

/tldr:

  1. Is there any difference between the 3 ways to make an empty array?
  2. What is the default capacity of an array when unspecified?
  3. What is the performance cost of using arrays with unspecified capacity?
3
  • The third slice myArr3 may be the most readable representation which just about anyone (including those who have little idea about GO) can understand. Arrays are different in Golang - array of a given size is "almost" like a type by itself, you can't equate/assign it with/to arrays of other sizes. It's better to get a good understanding of arrays - if you are new to Go "The Go Programming Language" by Donovan and Kernighan is also a good read. Commented Jul 26, 2017 at 5:51
  • Also unless there's a reason it's good to initialize the slice to the desired size, otherwise it's an additional cost (to allocate) when appending items. Commented Jul 26, 2017 at 6:01
  • Read it from the official wiki of Go github.com/golang/go/wiki/… Commented Jul 26, 2017 at 6:41

3 Answers 3

9

First, it's a slice not an array. Arrays and slices in Go are very different, arrays have a fixed size that is part of the type. I had trouble with this at first too :)

  1. Not really. Any if the three is correct, and any difference should be too small to worry about. In my own code I generally use whatever is easiest in a particular case.
  2. 0
  3. Nothing, until you need to add an item, then whatever it costs to allocate the storage needed.
Sign up to request clarification or add additional context in comments.

5 Comments

Ok so if I use var arr [0]int I have an array with 0 capacity, same with arr:=[0]int{} however if I do arr := make([]int,0,0) I get a slice. Seems wild. Am I correct to assume that you can only make slices and you cannot make arrays? What is the second argument to make?
Yup. Coming from C I found it really weird at first myself... Arrays in go code are actually really rare, slices are almost always better. (I'm not sure you can declare an array with size 0, never tried it) Take some time to read the go spec, it's nice and short and has tons of useful information! make only produces slices (and channels, but that is totally different). The second argument is the starting length of the slice, the third is it's maximum capacity before it need to reallocate itself. The third argument is optional.
Yes, you can declare an array with count == 0, which is weird to me since an array in C must have count >= 1. Arrays have their uses too, primarily in your own code. The golang.org/x/text/encoding/unicode package uses it in its unexported mibValue global variable. Note that many APIs require slices, so you likely want to use a slice for an exported identifier, but an array is fine if your identifier is unexported (nobody should be using it anyway, right? :)
A good example of an array in action is crypto/md5. A md5 checksum is always 16 bytes, so it makes perfect sense to use [16]byte to store one.
It is worth adding that myArr3 == nil is true, whereas it's false for myArr1 and myArr2.
7

What is the performance cost of using arrays with unspecified capacity?

There is certainly a cost when you start populating the slice. If you know how big the slice should grow, you can allocate capacity of the underlying array from the very begging as opposed to reallocating every time the underlying array fills up.

Here is a simple example with timing:

package main

import "fmt"

func main() {

    limit := 500 * 1000 * 1000
    mySlice := make([]int, 0, limit) //vs mySlice := make([]int, 0)

    for i := 0; i < limit; i++ {
        mySlice = append(mySlice, i)
    }

    fmt.Println(len(mySlice))
}

On my machine:

time go run my_file.go

With preallocation:

real    0m2.129s
user    0m2.073s
sys     0m1.357s

Without preallocation

real    0m7.673s
user    0m9.095s
sys     0m3.462s

1 Comment

Thanks for running the example!
2

Is there any difference between the 3 ways to make an empty array?

if empty array means len(array)==0, the answer is no, but actually only myArr3==nil is true.

What is the default capacity of an array when unspecified?

the default capacity will be same with the len you specify.

What is the performance cost of using arrays with unspecified capacity?

none

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.