Arrays, Slices & Maps at a Glance
Arrays are fixed-size values; slices and maps are reference-like collections built into the language.
Search across all documentation pages
Arrays are fixed-size values; slices and maps are reference-like collections built into the language.
Most Go code uses slices and maps daily, so len, cap, and sharing rules matter.
An array [N]T has size part of the type.
A slice []T is a header (pointer, len, cap) over an underlying array.
A map map[K]V is a hash table with undefined iteration order.
Slices and maps are passed by copying the header, so mutations are visible to callers.
Quick-reference recipe card - copy-paste ready.
package main
import "fmt"
func main() {
nums := make([]int, 0, 4)
nums = append(nums, 1, 2, 3)
ages := map[string]int{"ada": 36}
ages["grace"] = 34
fmt.Println(nums, len(nums), cap(nums), ages)
}When to reach for this:
make([]T, 0, n) when you know approximate size.package main
import "fmt"
func addSuffix(names []string, suffix string) {
for i := range names {
names[i] += suffix
}
}
func main() {
original := []string{"go", "rust"}
view := original[0:2:2] // full slice expression caps capacity
addSuffix(view, "!")
counts := map[string]int{}
for _, name := range original {
counts[name]++
}
fmt.Println(original, counts)
keys := make([]string, 0, len(counts))
for k := range counts {
keys = append(keys, k)
}
fmt.Println("keys (unordered):", keys)
}What this demonstrates:
addSuffix mutates original.s[low:high:max] limits append growth capacity.make or literals before writes.append grows capacity by allocating a new array when len == cap (typically doubling).s[low:high] sets len to high-low and cap to cap(s)-low.Array [n]T | Slice []T | Map map[K]V | |
|---|---|---|---|
| Size | Fixed in type | Dynamic | Dynamic |
| Pass to func | Copy whole array | Copy header | Copy header |
| Zero value | All elements zero | nil | nil |
| Comparable | Yes (if T comparable) | No | No |
| Index access | a[i] | s[i] | m[k] with ok form |
| Expression | Meaning |
|---|---|
len(s) | Number of elements visible in slice |
cap(s) | Elements from first index through end of backing array |
make([]T, len, cap) | Allocates array, sets len and cap |
append(s, x) | Grows len, may reallocate if len == cap |
// Delete map entry
delete(m, key)
// Clear map in Go 1.21+
clear(m)
// Copy slices
dst := make([]int, len(src))
copy(dst, src)a := []int{1,2,3}; b := a[:2]; append(b, 99) may overwrite a[2] if cap allows. Fix: use full slice a[:2:2] or append to a copy.make first.[5]int is not []int without slicing arr[:]. Fix: slice with [:].*[N]T or use slice.sync.Map or mutex.| Alternative | Use When | Don't Use When |
|---|---|---|
| Slice | Default ordered collection | Need O(1) lookup by key |
| Map | Keyed lookup | Need stable order without extra sort |
| Array | Fixed wire format size | General-purpose lists |
container/list | Frequent middle inserts (rare) | Most cases - slices win |
len is how many elements you can read/write from index 0.
cap is how many elements exist in the backing array starting at the slice's first element.
Yes - len and cap are 0, range works, and append allocates backing storage.
v, ok := m[key]
if !ok { /* missing */ }No - keys must be comparable; slices, maps, and functions are not comparable.
make([]T, 0, expected) then append, or make([]T, expected) if you will index directly.
Sets len to high-low and cap to max-low, preventing append from reading past max.
The entire array copies.
For [1024]byte buffers, pass a slice buf[:] or pointer instead.
No - &m[key] is illegal because map storage can move during growth.
Store value in a variable first if you need a pointer.
Loop and assign: for k, v := range other { m[k] = v }.
Watch for overwriting existing keys.
It may return a new header if reallocation happens.
Always assign: s = append(s, x).
Array is [0 0 0] value type.
Slice is nil header with no backing array.
append([]T(nil), s...) or s2 := make([]T, len(s)); copy(s2, s).
[]byte as byte slicesStack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 19, 2026