Slices: Capacity and Growth
tally collects words into a slice as it reads. Slices look like simple growable lists, and most of the time they behave like one. The exception — two slices quietly sharing memory — produces one of Go's most confusing bugs, and it is completely predictable once you can see a slice's three parts.
The rule
A slice is a window on an array: pointer, length, capacity.
A slice value holds three things:
- a pointer to an element of an underlying array,
- a length (
len): how many elements the window shows, - a capacity (
cap): how many elements exist from the start of the window to the end of the array.
Slicing shares. s[low:high] makes a new window on the same array. Its length is high - low, and its capacity runs to the end of the array: cap(s) - low.
words := []string{"the", "cat", "sat", "down"}
first := words[:2]
fmt.Println(len(first), cap(first)) // 2 4append uses spare capacity first. If len < cap, append writes into the existing array and returns a slice with a larger length. If there is no room, it allocates a new, larger array (often about double for small slices; the exact growth is up to the runtime), copies the elements across and returns a slice pointing there.
That is why you always write s = append(s, x): the result may point somewhere new.
Now the bug:
first = append(first, "ran")
fmt.Println(words) // [the cat ran down]first had room, so "ran" overwrote "sat" in the array both slices share.
The fix is to leave no spare room: the full slice expression words[:2:2] sets capacity to 2, so the next append must allocate. slices.Clone(words[:2]) makes a separate copy.
The shortcut
Before any append on a slice of a slice, write down (len, cap) and ask "is there room?" Room → it writes into shared memory. No room → it moves out to a new array.
The array
wordsis a 4-element array: the, cat, sat, down.
Drills
Answer fast — trust the rule.
s := []int{10, 20, 30, 40, 50}; t := s[1:3]. What are len(t) and cap(t)?
a := []int{1, 2, 3}; b := a[:1]; b = append(b, 7). What is a?
a := []int{1, 2, 3}; b := a[:1:1]; b = append(b, 7). What is a?
Why must you write s = append(s, x) rather than just append(s, x)?
Remember
- A slice is a window on an array: pointer, length, capacity.
- Shortcut: write down (len, cap) and ask "is there room?" before appending.
- Trap: appending to a sub-slice can overwrite the original;
s[a:b:b]orslices.Cloneprevents it.
