Slices
Arrays: the foundation
Section titled “Arrays: the foundation”An array in Go has a fixed size that is part of its type. [3]int and [4]int are two different types:
arr := [3]int{10, 20, 30}fmt.Println(len(arr)) // 3 — alwaysArrays are value types: assigning a2 := a1 copies every element. They are useful for fixed-size data but too rigid for most work.
Slices: the dynamic view
Section titled “Slices: the dynamic view”A slice is a lightweight header — three words — that describes a window into an underlying array:
flowchart LR
subgraph Header["slice header"]
P["pointer"]
L["len = 3"]
C["cap = 5"]
end
subgraph Backing["backing array"]
A0["10"] --> A1["20"] --> A2["30"] --> A3["40"] --> A4["50"]
end
P --> A0 len— number of elements currently accessible through the slice.cap— number of elements from the slice’s start to the end of the backing array.
Create a slice with make, a composite literal, or by slicing an array:
s := make([]int, 3, 5) // len=3, cap=5, all zerost := []int{1, 2, 3} // len=3, cap=3u := arr[1:3] // len=2, cap=2, window into arrappend and growth
Section titled “append and growth”append adds elements to a slice and returns the (possibly new) slice:
s = append(s, 4, 5, 6)When len == cap, append allocates a new, larger backing array, copies existing elements, and returns a slice pointing to the new array. The old slice is unaffected. Always reassign the result of append — s = append(s, ...).
Slicing expressions and shared backing arrays
Section titled “Slicing expressions and shared backing arrays”a[low:high] creates a new slice header that shares the same backing array:
base := []int{1, 2, 3, 4, 5}a := base[1:3] // [2 3] — shares backing array with baseb := base[1:4] // [2 3 4] — also sharesa[0] = 99fmt.Println(b[0]) // 99 — mutation visible through b tooThis is powerful (zero-copy sub-slicing) but dangerous if you forget about it.
copy for independent slices
Section titled “copy for independent slices”Use the built-in copy(dst, src) to break the sharing. It copies min(len(dst), len(src)) elements and returns the number copied:
fresh := []int{10, 20, 30}dst := make([]int, 3)copy(dst, fresh)dst[0] = 0fmt.Println(fresh[0], dst[0]) // 10 0 — independentpackage main
import "fmt"
func main() { // Array vs slice arr := [3]int{10, 20, 30} // fixed-size array sl := arr[:] // slice backed by arr sl[0] = 99 fmt.Println(arr[0], sl[0]) // 99 99 — shared backing array
// make: len and cap s := make([]int, 3, 5) fmt.Println(len(s), cap(s)) // 3 5
// append beyond cap allocates a new backing array s = append(s, 1, 2, 3) fmt.Println(len(s), cap(s)) // 6 10
// Two slices sharing the same backing array base := []int{1, 2, 3, 4, 5} a := base[1:3] // [2 3] b := base[1:4] // [2 3 4] a[0] = 99 fmt.Println(b[0]) // 99 — shared backing array
// copy to get an independent slice fresh := []int{10, 20, 30} dst := make([]int, 3) copy(dst, fresh) dst[0] = 0 fmt.Println(fresh[0], dst[0]) // 10 0 — independent after copy}Loading Go runtime (first run only, ~8 MB)…