Go

What is the difference between a nil slice and an empty slice? When does it matter?

Question 45MediumGo 1.22 to 1.25

var s []int is nil: ptr is nil, len and cap are 0. s := []int{} or make([]int, 0) is empty but non-nil: ptr points at a zero-size allocation (often runtime.zerobase). For almost everything they act the same: len, cap, range, append, and slicing s[0:0] all work on nil.

They differ in these places:

var a []int
b := []int{}

fmt.Println(a == nil, b == nil)       // true false
j1, _ := json.Marshal(a)              // null
j2, _ := json.Marshal(b)              // []
fmt.Println(string(j1), string(j2))
fmt.Println(reflect.DeepEqual(a, b))  // false
fmt.Println(slices.Equal(a, b))       // true (length-based)
  • JSON/API contracts: null and [] can break frontend clients. That is a common production bug.
  • Tests: reflect.DeepEqual and testify's Equal tell them apart.
  • Interfaces: a nil []int stored in any is a non-nil interface.

Idiom: prefer var s []T (the Go Code Review Comments guideline). Check emptiness with len(s) == 0, never s == nil. Initialize to []T{} only when the encoded form matters.

More on Arrays, Slices, Maps & Strings

All 37 Arrays, Slices, Maps & Strings questions