ProgrammingGo Developer

What are the built-in functions append, len, and cap in Go, how do they work at the language level, and what hidden dangers related to slices are associated with their use?

Pass interviews with Hintsage AI assistant

Answer

In Go, the built-in functions append, len, and cap play a key role when working with slices.

  • len(slice) returns the number of elements in the slice.
  • cap(slice) returns the capacity of the slice — the maximum number of elements before new memory allocation.
  • append(slice, elems ...T) can lead to the creation of a new array (and thus a new backing store) if the capacity is insufficient, which may unexpectedly change the semantics of slice passing.

Example:

arr := []int{1,2,3} arr2 := append(arr, 4) // arr2 may be on the same or a new backing array, depending on cap(arr)

Nuances:

  • If you append to a slice that was "sliced" from another slice (or original array), there can be a side effect: changing the original data.
  • When passing slices to functions, len/cap only applies to the "visible" part.
  • When appending exceeding cap, a new array is created, the old one remains untouched.

Trick Question

What happens if you "slice off" a piece of a slice and add an element via append? Will it affect the original array?

Answer: If cap allows, append will write the element "at the tail" of the original array, and the changes will be visible through all slices that refer to the same array.

Example:

a := []int{1,2,3,4} b := a[:2] // [1 2], len=2, cap=4 b = append(b, 10) // a changes: a -> [1, 2, 10, 4]

Examples of Real Errors


Story

In the team, elements were added to a child slice, and unexpectedly the data in the parent array changed — this caused a mismatch in business logic and complex-to-debug bugs in the distribution of tasks among users.


Story

Upon repeated calling of append on a large slice, it was expected that a new array would always be allocated, but in fact, several parts of the system continued to work with the same "backing array", provoking race conditions and data corruption.


Story

A developer allocated a fixed-size slice using make, but made an error and swapped the arguments: make([]int, cap, len). As a result, logic oriented on capacity unexpectedly operated on length, causing a panic when going beyond s[0:len].