A common mistake is treating a slice’s capacity as the number of elements you can index. Length counts the elements currently in the slice; capacity counts the backing-array space available from the slice’s starting position. A slice holds a reference to that array along with its length and capacity. Space beyond the length is allocated but cannot be indexed until the slice grows. section 3.4
Allocated does not mean indexable
s := make([]int, 3, 6) s[1] = 1 // valid: length remains 3 // s[4] = 0 // panic: index out of range s = append(s, 2) // uses available capacity; length becomes 4 section 3.4
Slicing does not necessarily allocate a new array. Two slices can start at different positions in the same backing array, so they can have different lengths and capacities while sharing elements. Changes to a shared element are visible through both slices. An append that fits within available capacity can also write to their shared array; once that array is full, appending creates another array and copies the elements. section 3.4
Figure 3.6 The slices s1 and s2 reference the same backing array with different lengths and capacities.
The diagram locates two slices in one backing array, making their different starting positions, lengths, and capacities visible. section 3.4
Choose the allocation strategy to match how the result will be filled:
- If you will append a known number of elements, use make([]Bar, 0, n). Reserving capacity avoids repeatedly allocating backing arrays as the slice grows. section 3.5
- If you will fill positions by index, use make([]Bar, n) and assign bars[i]. Those n positions already belong to the slice; appending instead would add elements after them. section 3.5
Avoid repeated growth
func convert(foos []Foo) []Bar { bars := make([]Bar, 0, len(foos)) for _, foo := range foos { bars = append(bars, fooToBar(foo)) } return bars } Starting with an empty slice without reserved capacity makes this conversion allocate and copy backing arrays as it grows. Here, the output size is known, so one capacity reservation fits the append-based implementation. section 3.5
Capacity also matters when a slice is shortened. Returning foos[:2] from a large slice retains its backing array. If excluded elements contain pointers or slice fields, their referenced data can remain in memory even though those elements are outside the new length. Copy the wanted elements into a new slice to release the old backing array, or clear the excluded pointer-bearing fields before returning a slice of the original array. Use a copy when the result must not retain the old array; clear fields when sharing that array is acceptable. section 3.10.2 section 3.14




