An array’s length is part of its type ([5]int and [10]int are different types), which makes arrays inflexible and rarely used directly. A slice is a small struct — a pointer to an underlying array, a length, and a capacity — that provides a flexible, growable view over that array, and is what idiomatic Go code uses for lists in practice. len(s) reports how many elements a slice currently holds; cap(s) reports how many it could hold before its backing array must be reallocated.
Arrays: fixed size, part of the type
An array's length is fixed at compile time and is part of its type. This makes arrays value types — assigning or passing one copies every element — which is exactly why Go code almost always uses slices instead.
var scores [3]int // array of exactly 3 ints, zero-valued
scores[0] = 90
primes := [5]int{2, 3, 5, 7, 11}
fmt.Println(len(primes)) // 5 — fixed forever for this variableSlices: a view over an array
A slice is created with []T{...} literal syntax, make([]T, len, cap), or by slicing an existing array/slice with a[low:high]. Two slices can share the same underlying array — mutating one through indexing can be visible through the other, since neither owns a private copy.
nums := []int{10, 20, 30, 40, 50} // slice literal
sub := nums[1:3] // [20, 30] — shares nums' backing array
sub[0] = 999
fmt.Println(nums) // [10, 999, 30, 40, 50] — nums changed too!append() and when a slice grows
append adds elements to a slice. If the slice still has spare capacity, append writes into the existing backing array and returns a slice pointing at the same array. If capacity is exhausted, Go allocates a new, larger backing array (typically doubling for smaller slices), copies the old data over, and returns a slice pointing at the new array — which is why append's result must always be reassigned, since the original variable's backing array may no longer be the current one.
s := make([]int, 0, 2) // len 0, cap 2
s = append(s, 1) // fits: len 1, cap 2, same backing array
s = append(s, 2) // fits: len 2, cap 2, same backing array
s = append(s, 3) // doesn't fit: Go allocates a new, bigger array
// always reassign: s := append(s, x) NOT append(s, x) alone