Es Append Grow A Slice Internally
Fast recall
Quick revision
Core answer
Practical understanding of Slice Internals Len Cap.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
Append has exactly two modes. With capacity spare, it's a store: write the element at index len, bump len, return the same header. No allocation, no copy — and critically, every slice sharing that backing array sees the change.
At capacity, append grows: allocate a new array (roughly double the current capacity for small slices — a 3-cap slice grows to 6), copy the existing elements over, append the new one, and return a header pointing at the new storage. The old array is abandoned — slices still viewing it are now forked and won't see the new element or any future changes.
Because append can go either way, its return value is the only reliable handle: s = append(s, x). When growth happened, the returned header points at the new array; ignoring the return keeps using the old, stale header and silently drops elements.
Es Append Grow A Slice Internally
Direct Answer
If len < cap, append writes into the spare slot — no allocation. At len == cap, it allocates a bigger array (~2x small slices), copies, and returns the new header. The result must be reassigned.
Deep Dive & Architecture
The doubling strategy is the classic amortized-constant trick from dynamic arrays: appending n elements with naive 1-slot growth costs O(n²) total copies; doubling means each element is copied O(1) times on average. Go tapers the factor for very large slices (where 2x over-allocates gigabytes) but small slices get ~2x.
You can observe both modes with cap prints:
s := make([]int, 0, 3) // cap 3 from the start
s = append(s, 1) // fits: cap still 3
s = append(s, 2) // fits: cap still 3
s = append(s, 3) // fits exactly: cap still 3
s = append(s, 4) // full: new array, cap now 6
fmt.Println(len(s), cap(s)) // 4 6
The gotcha this mechanism creates: append below capacity mutates shared state. t := s[:2]; t = append(t, 42) writes into s's backing array if the slot exists — s sees a changed element it never touched. That's not a bug in append; it's the in-place mode doing exactly what it's for. The fix when sharing isn't wanted is a real copy (make + copy or append(nil, s...)), which forces the allocate-mode behavior on purpose.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Slice Internals Len Cap, and when would you use it?
- When would you use Slice Internals Len Cap in a real project?
- How would you compare Slice Internals Len Cap with an alternative?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.