Slices and maps

Arrays versus slices, the backing-array trap, and how maps behave when a key is missing.

Slices

An array has a fixed length that is part of its type. A slice is a small header — pointer, length and capacity — describing a window over a backing array.

var grid [3][3]int                 // array: fixed size, copied on assignment

s := make([]int, 0, 4)             // slice: len 0, cap 4
s = append(s, 10, 20, 30)

fmt.Println(len(s), cap(s))        // 3 4

head := s[:2]                      // shares the backing array
head[0] = 99                       // so s[0] is now 99 too

safe := make([]int, len(s))        // copy when you need independence
copy(safe, s)

bounded := s[0:2:2]                // three-index slice: appends cannot clobber s[2]
OperationCost and notes
append(s, v)Amortised O(1); may allocate a new array and copy
s[i]O(1) index access
s[a:b]O(1); shares memory with s
copy(dst, src)O(n) over min(len(dst), len(src))
append(s[:i], s[i+1:]...)O(n) delete from the middle
⚠️
A slice shares its backing array. Appending through a sub-slice can overwrite elements you thought were safe, and keeping a one-element sub-slice of a huge slice keeps the whole array alive in memory. Copy, or use the three-index form.

Maps

ages := map[string]int{"ada": 36, "grace": 45}
ages["alan"] = 41

v, ok := ages["missing"]        // comma-ok: v is 0, ok is false
if !ok {
    fmt.Println("no such key")
}

delete(ages, "alan")

for name, age := range ages {   // iteration order is deliberately random
    fmt.Println(name, age)
}

counts := map[string]int{}
counts["a"]++                   // zero value makes this safe with no init
  • Reading a missing key returns the zero value, never an error. Use the comma-ok form whenever presence matters, because a stored zero and a missing key are different facts.
  • A nil map can be read but writing to it panics. Always make it or use a literal before assigning.
  • Iteration order is randomised on purpose, so never depend on it. Sort the keys first when output must be stable.
  • Maps are reference types: passing one to a function shares it. Guard concurrent access with sync.Mutex or use sync.Map.
  • maps.Keys, maps.Clone and slices.Sort from the standard library replace a lot of hand-written loops.

FAQ

Slice or array?
Use slices almost always: they grow, they are cheap to pass, and they work with the standard library. Arrays are useful for fixed buffers and as map keys, since their length is part of the comparable type.
Why does my program panic with 'assignment to entry in nil map'?
You declared a map with var m map[string]int and never allocated it. Reading from a nil map is fine, writing is not. Add m = make(map[string]int).

Go syntax, types and functions Goroutines and channels

Last refreshed 2026-09-18.