Under The Hood
backend go Go 1.21+

Go slices: the three-word header

Last updated
Prerequisites:
Go basics: arrays, slices, functions
Understanding of value semantics vs reference semantics
  • go
  • slices
  • memory
  • arrays
  • aliasing
  • append

Read at your depth

The practical view

A slice is a struct of three words: a pointer to the underlying array, len (length: how many elements are valid), and cap (capacity: how many fit before reallocation). s := make([]int, 3, 5) has len 3, cap 5. append(s, v) writes at s[len] if len < cap; when len == cap, it allocates a new array (usually doubling capacity), copies, and returns a NEW slice header — which is why you must assign the result: s = append(s, v). Slices are passed by value (the header is copied) but share the underlying array, so mutating elements inside a function is visible to the caller.

Legacy vs modern

Aliasing append into a sub-slice vs explicit capacity control

A shared backing array turns a local append into a caller-visible mutation; the full slice expression or a fresh copy restores isolation.

before → after
Shared backing array
a := make([]int, 2, 4) // len 2, cap 4
b := a[:2]
b = append(b, 9)     // writes INTO a's array
Isolated copy
b := append([]T(nil), a[:n]...) // fresh backing array

Interview gotchas

Under The Hood — a multi-depth technical interview hub.

Press ⌘ K to search.