Slices are Go's everyday list type; almost every program uses them.
An array has a fixed length that is part of its type: [3]int and [4]int are different types. Arrays are values — assigning or passing one copies every element — so you rarely use them directly.
A slice, []int, is a lightweight view onto an underlying array: a pointer, a length and a capacity. You create one with a literal ([]int{1, 2, 3}), with make([]int, len, cap), or by slicing an array or slice: s[low:high] contains elements low up to but not including high.
len(s)is the number of elements you can index;cap(s)is how far it can grow before reallocating.append(s, x, y)returns a slice with the elements added. If capacity runs out it allocates a bigger array and copies. Always assign the result:s = append(s, x).- A nil slice (
var s []int) has length 0 and works fine withlen,rangeandappend— no need to initialise it. - Indexing beyond
lenpanics at run time.
Because slicing shares the underlying array, t := s[1:3] and s see each other's writes. Use copy(dst, src) or slices.Clone(s) when you need an independent copy.
The standard slices package (Go 1.21+) provides the common helpers: slices.Sort, slices.Contains, slices.Index, slices.Reverse, slices.Max. Reach for it before writing a loop.
Example
package main
import (
"fmt"
"slices"
)
func main() {
var nums []int // nil slice, ready to use
for i := range 5 {
nums = append(nums, i*i)
}
fmt.Println(nums, len(nums)) // [0 1 4 9 16] 5
mid := nums[1:4] // shares memory with nums
mid[0] = 100
fmt.Println(nums[1]) // 100
c := slices.Clone(nums)
slices.Reverse(c)
fmt.Println(c, slices.Contains(c, 9)) // [16 9 4 100 0] true
}Remember
- A slice is a (pointer, len, cap) view onto an array
- Always write
s = append(s, ...) - Sub-slices share memory; clone when you need independence
Watch out for
- Calling
append(s, x)without assigning the result — the new element is lost.