150

In Go, what is the difference between var s []int and s := make([]int, 0)?

I find that both works, but which one is better?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Wang Yi
  • 1,777
  • 3
  • 13
  • 6
  • The first one creates a `nil` slice, whereas the second creates an `empty` slice (this is the terminology used by the *"Go in action book"*). To avoid posting the same answer here too, you can check https://stackoverflow.com/a/45997533/1561148 – tgogos Sep 01 '17 at 10:30

4 Answers4

160

Simple declaration

var s []int

does not allocate memory and s points to nil, while

s := make([]int, 0)

allocates memory and s points to memory to a slice with 0 elements.

Usually, the first one is more idiomatic if you don't know the exact size of your use case.

030
  • 10,842
  • 12
  • 78
  • 123
fabrizioM
  • 46,639
  • 15
  • 102
  • 119
  • 1
    Can i say the same for map? var m map[string]int vs m:= make(map[string]int) ? Thanks. – joshua Mar 06 '15 at 07:46
  • 18
    Nah, you need to `make` maps, because even an empty `map` needs space allocated for some bookkeeping. – twotwotwo Aug 07 '15 at 20:09
  • 13
    If you need to return a slice with 0 elements (instead of 'nil'), make is the correct usage. – Jess Apr 21 '16 at 15:28
  • The other alternative for map is to declare an empty map literal, which is functionally the same as `make(..)` except that there is no option to specify the initial size. https://play.golang.org/p/gn1kVAfZcS – nishanthshanmugham Jul 01 '16 at 14:40
  • 9
    If you're building an API and return an array as the response, using the declarative form will return `nil` in case your slice doesn't have any element, rather than an empty array. However, if `make` is used to create the slice, an empty array will be returned instead, which is generally the desired effect. – robinmitra Nov 21 '17 at 18:19
  • 10
    As mentioned in a comment on this answer: https://stackoverflow.com/a/29164565/1311538, there are differences when attempting to do things like json marshaling. Marshaling the nil slice (`var s []int`) will produce `null`, while marshaling the empty slice (`s := make([]int, 0)`) will produce the expected `[]` – asgaines Aug 26 '18 at 19:01
  • Does anyone know why `make` is not applied automatically? We always need memory and point to it to use the variable. So why is `make` part of the language at all? – kev Sep 24 '18 at 01:47
  • May I ask what is this one: `s := []float64{5, 6, 7}`, I use it a lot yet doesn't quite understand it. – Archeosudoerus Jul 25 '19 at 14:31
  • i find the latter way is quite useful when api want to response empty array as default – Nhan Tran Feb 19 '20 at 07:35
  • `make` won't allocate if len is zero, there is no concept of allocating zero bytes. Pointers to zero sized things will have a shared specific address in Go. – Arman Ordookhani Apr 21 '20 at 14:24
111

In addition to fabriziom's answer, you can see more examples at "Go Slices: usage and internals", where a use for []int is mentioned:

Since the zero value of a slice (nil) acts like a zero-length slice, you can declare a slice variable and then append to it in a loop:

// Filter returns a new slice holding only
// the elements of s that satisfy f()
func Filter(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

It means that, to append to a slice, you don't have to allocate memory first: the nil slice p int[] is enough as a slice to add to.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Why you think it would do an allocation? Cap is zero so nothing is allocated with or without make. – Arman Ordookhani Apr 21 '20 at 14:19
  • 1
    @ArmanOrdookhani Agreed. I just find the declaration `var p []int` easier than using `make` (which I associate more with allocation, even though with a 0 cap, it would not allocate anything). In term of readability, I prefer not using `make` here. – VonC Apr 21 '20 at 14:24
  • 2
    I'm more toward using literals everywhere (e.g. `p := []int{}`). Since we usually use `:=` syntax to declare most variables, it's more natural to have it everywhere instead of having an exceptions for slices. Other than this trying to think of allocations usually push people toward premature optimizations. – Arman Ordookhani Apr 21 '20 at 14:33
23

Just found a difference. If you use

var list []MyObjects

and then you encode the output as JSON, you get null.

list := make([]MyObjects, 0)

results in [] as expected.

Steve Hanov
  • 11,316
  • 16
  • 62
  • 69
8

A bit more complete example (one more argument in .make()):

slice := make([]int, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Out:

length:  2 - capacity 5 - content:  [0 0]

Or with a dynamic type of slice:

slice := make([]interface{}, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Out:

length:  2 - capacity 5 - content:  [<nil> <nil>]
Benyamin Jafari
  • 27,880
  • 26
  • 135
  • 150