Go

Explain nil map behaviour and what happens when you pass a map to a function.

Question 66MediumGo 1.22 to 1.25

A map variable is a pointer to a runtime header. Passing it copies the pointer, so inserts and deletes inside the callee are visible to the caller, without needing *map. Reassigning the parameter (m = make(...)) affects only the callee's copy.

A nil map acts as an empty, read-only map. Reads return the zero value, and len, range, delete and clear all work. Writes panic with assignment to entry in nil map.

func fill(m map[string]int) { m["a"] = 1 }
func reset(m map[string]int) { m = map[string]int{} } // no effect on caller

func main() {
	var nilMap map[string]int
	fmt.Println(nilMap["x"], len(nilMap)) // 0 0
	delete(nilMap, "x")                   // OK, no-op
	for range nilMap {}                   // OK
	// nilMap["x"] = 1                    // panic: assignment to entry in nil map

	m := map[string]int{}
	fill(m)
	reset(m)
	fmt.Println(m) // map[a:1]
}

// Common bug: struct with a map field used via its zero value
type Registry struct{ items map[string]int }
func (r *Registry) Add(k string) {
	if r.items == nil { // lazy init makes the zero value usable
		r.items = make(map[string]int)
	}
	r.items[k]++
}

Signal: you design types so their zero value is useful (lazy init, like sync.Mutex or bytes.Buffer). When decoding JSON into a struct, remember that nested map fields start as nil until the decoder allocates them.

More on Arrays, Slices, Maps & Strings

All 37 Arrays, Slices, Maps & Strings questions