Reading — step 1 of 8
Learn
Slices are Go's go-to ordered collection — and the most-misunderstood part of the language. Get them right and you write idiomatic Go. Get them wrong and you write subtle aliasing bugs.
Mental model: a slice is a 3-field header
A slice value has three components:
- pointer to the start of an underlying array
- length — how many elements are visible
- capacity — how many elements fit before reallocation
Multiple slices can SHARE the same underlying array. That's the gotcha.
Creating slices
make([]T, len, cap) pre-allocates capacity — useful when you know you'll grow the slice.
Slice expressions — s[low:high]
Slice expressions DON'T copy the data — they create a NEW slice header pointing at the same memory.
⚠️ The aliasing trap
Mutating through view mutates base because they share memory. To make an independent copy:
append — and the capacity surprise
Always assign the result of append back. Why? When the slice's capacity is exceeded, append allocates a NEW array and copies. The old slice header still points to the old array.
This is why "shared underlying array" is so subtle — it depends on whether append reallocated.
Iterate with range
A range loop on a slice copies the value — modifying v doesn't change the slice. Use nums[i] if you need to write.
Common operations
Nil slices vs empty slices
You can append to a nil slice without checking. Functionally identical for most purposes.
Common mistakes
- Forgetting to assign
appendback:append(nums, 5)does nothing visible if cap was exceeded. - Shared underlying array bugs:
view := base[1:3]shares memory. Copy explicitly when needed. - Slicing past the underlying array's capacity: panics. Use
nums[:cap(nums)]to extend within capacity. rangevalue is a COPY: modifyingvinfor _, v := range nums { v = 0 }does nothing.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…