Slices, maps and strings · 3 MIN READ

A nil slice is empty, and append still works

Predict what len, == nil and append do to a zero slice.

The Tour's "Nil slices" page: the zero value of a slice is nil, it has length and capacity 0, and it has no backing array. append treats that as a valid empty slice and allocates. JSON encodes a nil slice as null and a non-nil empty one as [] — the only common place the distinction leaks out.

s == nil is true for var s []int and false for s := []int{}. Both have len 0. Prefer len(s) == 0 unless you are talking to a wire format that cares.

SEE THE IDEA

A nil slice already supports empty operations

  1. 01

    Start

    go
    var values []int

    Length and capacity are zero

  2. 02

    Grow

    go
    values = append(values, 9)

    Append allocates when needed

  3. 03

    Use

    go
    range values

    An empty slice runs zero iterations

Nil and empty slices behave alike for length, range and append.

In practice

Return a nil slice when no results is a natural zero value, unless the API requires a non-nil empty value. Most callers should inspect length rather than compare to nil. Encoders may distinguish the two representations, so document the serialized contract when it matters.

Watch out

The standard encoding/json package encodes a nil slice as null and a non-nil empty slice as [].

Official reference ↗

Read and predict

go
package main

import "fmt"

func main() {
	var s []int
	fmt.Println(s == nil, len(s), cap(s))
	s = append(s, 1)
	fmt.Println(s == nil, len(s), s[0])
	empty := []int{}
	fmt.Println(empty == nil, len(empty))
}

What does this print?

Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.