445

To declare an empty slice, with a non-fixed size, is it better to do:

mySlice1 := make([]int, 0)

or:

mySlice2 := []int{}

Just wondering which one is the correct way.

2
  • 3
    You say "non-fixed size", but slices are never have a fixed size. Unless you mean with zero capacity. Note, if you have an idea/guess/hint of what capacity you might need then using the three argument version is good. E.g. to build a slice of map keys: keys := make([]int, 0, len(m)); for k, v := range m { keys := append(keys,k) } Commented Mar 20, 2015 at 18:06
  • 1
    Possible duplicate of Declare slice or make slice? Commented Nov 21, 2015 at 0:08

6 Answers 6

494

The two alternative you gave are semantically identical, but using make([]int, 0) will result in an internal call to runtime.makeslice (Go 1.16).

You also have the option to leave it with a nil value:

var myslice []int

As written in the Golang.org blog:

a nil slice is functionally equivalent to a zero-length slice, even though it points to nothing. It has length zero and can be appended to, with allocation.

A nil slice will however json.Marshal() into "null" whereas an empty slice will marshal into "[]", as pointed out by @farwayer.

None of the above options will cause any allocation, as pointed out by @ArmanOrdookhani.

Sign up to request clarification or add additional context in comments.

8 Comments

Also mention on wiki github.com/golang/go/wiki/…
Be care: json.Marshal() will return null for var myslice []int and [] for initialized slice myslice := []int{}
Also be careful: reflect.DeepEqual makes a distinction between nil slices and non-nil slices: a := []int{}, var b []int, reflect.DeepEqual(a, b) // returns false
Why you think it would do an allocation? Cap is zero so nothing is allocated. All pointers to zero length things point to the same location in memory: play.golang.org/p/MPOKKl_sYvw
@КонстантинВан As of Go 1.16, they don't produce identical code, as you can see here. Using make calls runtime.makeslice, even for a zero-length slice, while the empty slice literal directly uses runtime.zerobase. Meaning, the literal is slightly faster in Go 1.16.
|
135

They are equivalent. See this code:

mySlice1 := make([]int, 0)
mySlice2 := []int{}
fmt.Println("mySlice1", cap(mySlice1))
fmt.Println("mySlice2", cap(mySlice2))

Output:

mySlice1 0
mySlice2 0

Both slices have 0 capacity which implies both slices have 0 length (cannot be greater than the capacity) which implies both slices have no elements. This means the 2 slices are identical in every aspect.

See similar questions:

What is the point of having nil slice and empty slice in golang?

nil slices vs non-nil slices vs empty slices in Go language

Comments

72

As an addition to @ANisus' answer...

below is some information from the "Go in action" book, which I think is worth mentioning:

Difference between nil & empty slices

If we think of a slice like this:

[pointer] [length] [capacity]

then:

nil slice:   [nil][0][0]
empty slice: [addr][0][0] // points to an address

nil slice

They’re useful when you want to represent a slice that doesn’t exist, such as when an exception occurs in a function that returns a slice.

// Create a nil slice of integers.
var slice []int

empty slice

Empty slices are useful when you want to represent an empty collection, such as when a database query returns zero results.

// Use make to create an empty slice of integers.
slice := make([]int, 0)

// Use a slice literal to create an empty slice of integers.
slice := []int{}

Regardless of whether you’re using a nil slice or an empty slice, the built-in functions append, len, and cap work the same.


Go playground example:

package main

import (
    "fmt"
)

func main() {

    var nil_slice []int
    var empty_slice = []int{}

    fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
    fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))

}

prints:

true 0 0
false 0 0

2 Comments

Can we get the address of empty slice in one step using make?
If we take a look at the function signature, make doesn't seem to return the address. I believe you can't do it in one step.
19

Empty slice and nil slice are initialized differently in Go:

var nilSlice []int 
emptySlice1 := make([]int, 0)
emptySlice2 := []int{}

fmt.Println(nilSlice == nil)    // true
fmt.Println(emptySlice1 == nil) // false
fmt.Println(emptySlice2 == nil) // false

As for all three slices, len and cap are 0.

2 Comments

make([]int, 0) is the best because Jetbrains GoLand does not complain about it being "unnecessary" as it does in the case of []int{}. This is useful in writing unit tests.
I don't think we should decide best practices based on what IDE developers' opinions.
2

In addition to @ANisus' answer

When using the official Go MongoDb Driver, a nil slice will also marshal into "null" whereas an empty slice will marshal into "[]".

When using using the community supported MGO driver, both nil and empty slices will be marshalled into "[]".

Reference: https://jira.mongodb.org/browse/GODRIVER-971

Comments

-1

This is the shortest way to initialize empty slice.

list := []int{}

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.