ProgrammingBackend Developer

Describe the features of working with slices in Go: what is a nil slice, what is the difference between length and capacity, and how to properly increase a slice without leaking data or causing panic?

Pass interviews with Hintsage AI assistant

Answer.

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:

  • Nil slice (var s []int) does not allocate any memory at all, differing from an empty slice (make([]int, 0)) only internally.
  • Length shows the current count of elements, while capacity indicates the maximum without additional allocation.
  • When appending, if the capacity is insufficient, a new one is created under the hood, while the old data remains unchanged.

Tricky questions.

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

Common mistakes and anti-patterns

  • Errors when passing a nil slice or empty slice to a function that requires a specific length.
  • Overfilling a slice without considering capacity growth and poorly structured loops with append.
  • Attempts to assign by index instead of using append to add elements.

Real-life example

Negative case

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:

  • Fewer memory allocations at start.

Cons:

  • Incorrect JSON handling (resulting in null instead of an array).
  • Runtime errors when accessing by index.

Positive case

Using make([]T, 0, 100) for preallocation, and then only append in a loop. This minimizes memory allocations and often improves performance.

Pros:

  • Efficient memory usage.
  • No panics and unexpected values during marshaling.

Cons:

  • Possible memory overrun if the expected number of elements does not match the given capacity.