Go Slices & Arrays
Arrays vs Slices
var a [5]int // 5 zeros
b := [3]string{"x", "y", "z"}
c := [...]int{1, 2, 3} // size inferred from elements
// Arrays are values — assignment copies
d := b
d[0] = "changed"
fmt.Println(b[0]) // "x" — b is unchanged
Arrays have a fixed size that is part of the type: [3]int and [5]int are different types. You almost never use raw arrays — slices are the idiomatic choice.
Creating Slices
// Literal
s := []int{10, 20, 30}
// make(type, length, capacity)
buf := make([]byte, 0, 1024) // len=0, cap=1024
// nil slice — valid, zero length
var empty []int
fmt.Println(len(empty)) // 0
fmt.Println(empty == nil) // true
make pre-allocates capacity without filling it. A nil slice is functionally identical to an empty slice for most operations — len, cap, range, and append all work correctly on nil slices.
Append & Growth
s := []int{1, 2, 3}
s = append(s, 4) // always reassign
s = append(s, 5, 6, 7) // variadic
// Append one slice to another
more := []int{8, 9}
s = append(s, more...) // unpack with ...
append may allocate a new backing array if capacity is exceeded. Always capture the return value: s = append(s, …). Forgetting the assignment is a common bug.
Slicing Operations
data := []int{0, 1, 2, 3, 4, 5}
sub := data[1:4] // [1, 2, 3] — indices 1, 2, 3
head := data[:3] // [0, 1, 2]
tail := data[3:] // [3, 4, 5]
all := data[:] // full slice — same backing array
// Full slice expression — limits capacity
safe := data[1:4:4] // len=3, cap=3 — append won't overwrite data[4]
Slices share the underlying array. Modifying sub[0] changes data[1]. The three-index slice [low:high:max] controls capacity, preventing append from overwriting adjacent elements.
Common Patterns
func remove(s []int, i int) []int {
return append(s[:i], s[i+1:]...)
}
func filter(s []string, pred func(string) bool) []string {
result := s[:0] // reuse backing array, zero length
for _, v := range s {
if pred(v) {
result = append(result, v)
}
}
return result
}
s[:0] creates a zero-length slice backed by the same array — avoids allocation when the result is smaller than the input.