A slice is a dynamic array, the primary structural unit when working with arrays in Go. Historically, programming languages have offered fixed arrays or more cumbersome structures. Go has implemented slices as a convenient tool for handling collections of memory with automatic size management and the ability to change length.
The problem lies in proper memory management, handling edge cases (empty, nil, full slices), and understanding the difference between the length and capacity of a slice.
The solution is to correctly use the built-in functions len(), cap(), and operate on slices according to Go conventions.
Example code:
var a []int // nil slice, len=0, cap=0 b := make([]int, 0) // empty slice, len=0, cap=0 c := make([]int, 3, 5) // len=3, cap=5 c = append(c, 4, 5, 6) // cap will increase automatically
Key features:
var s []int) does not allocate any memory at all, differing from an empty slice (make([]int, 0)) only internally.What will the length and capacity of a slice be after appending to a nil slice?
Nil slice (var s []int) becomes a slice of length 1, capacity 1 after append(s, 1) — Go allocates storage itself.
var s []int s = append(s, 42) // s is now [42], len=1, cap=1
Can you access the capacity of a nil slice?
Yes, for a nil slice, both functions — len and cap — return 0. There will be no panic.
var s []int fmt.Println(len(s), cap(s)) // 0 0
What happens when trying to assign to an element by index without prior memory allocation for a nil slice?
A panic index out of range, because the slice has no elements.
var s []int s[0] = 1 // panic: runtime error: index out of range
The team decided to use var s []T everywhere in the Go server, expecting it to always be equivalent to make([]T, 0). As a result, some JSON marshaling returned null instead of [].
Pros:
Cons:
Using make([]T, 0, 100) for preallocation, and then only append in a loop. This minimizes memory allocations and often improves performance.
Pros:
Cons: