liveBook · Manning

Nil slice

As explained in 100 Go Mistakes and How to Avoid Them

A nil slice is a slice whose value is nil and whose length is zero without requiring an underlying allocation.

A nil slice equals `nil` and has length zero. An empty slice also has length zero, but it need not be nil. Confusing the two can turn a check for elements into a check for how the slice was initialized. section 3.6 section 3.7

func main() {
    var s []string         #1
    log(1, s)
 
    s = []string(nil)      #2
    log(2, s)
 
    s = []string{}         #3
    log(3, s)
 
    s = make([]string, 0)  #4
    log(4, s)
}
 
func log(i int, s []string) {
    fmt.Printf("%d: empty=%t\tnil=%t\n", i, len(s) == 0, s == nil)
}

Compare four zero-length initializations: `var s []string` and `[]string(nil)` are nil; `[]string{}` and `make([]string, 0)` are not. section 3.6

Prefer `var s []string` when a function might return no elements: a nil slice needs no allocation, and `append` still works on it. If the result length is known, use `make([]string, length)` instead to avoid extra allocations and copies. section 3.6

A presence check that handles both forms

Suppose `getOperations` returns `make([]float32, 0)` when there are no operations. `if operations != nil { handle(operations) }` still calls `handle`. Use `if len(operations) != 0 { handle(operations) }`: it excludes both nil and non-nil empty slices without requiring a change to `getOperations`. APIs should not give nil and empty slices different meanings for callers. section 3.7

When the distinction is observable

`encoding/json` marshals a nil slice field as `null` and a non-nil empty slice field as `[]`. Check that output when the JSON representation matters, even though both slices contain no elements. section 3.6

A nil slice can also be an `append` destination: `dst := append([]int(nil), src...)` copies the elements of `src`. When using `copy` instead, give the destination enough length; copying into `var dst []int` copies no elements. section 3.8

How 100 Go Mistakes and How to Avoid Them covers it

How deep it goes
Defines nil versus empty, compares initializations, and traces allocation, append, JSON encoding, and presence checks without examining slice representation.
Examples
Contrasts four zero-length initializations, an operations-handling bug, JSON `null` versus `[]`, and copying into a nil slice.
What it assumes
Assumes familiarity with basic Go slice and function syntax; defines nil and empty slices before comparing their behavior.
What you can do after
Diagnose/debug with it by checking `len` for elements and recognizing when nil versus non-nil empty changes JSON output.
How it connects
Connects slice length and capacity to append, allocation, encoding/json, API design, and slice copying.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Go Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.