slices, maps, cmp, and iter
slices, maps, cmp, and iter
Overview
Go 1.21+ added first-class helpers for common collection work. Go 1.23 popularized range-over-func iterators via package iter.
| Package | Role |
|---|---|
slices |
Search, sort, clone, compact, delete |
maps |
Keys/values clone, equal, copy |
cmp |
Ordered comparisons for sort helpers |
iter |
Seq / Seq2 iterator types |
Basics of ranging: Loops.
slices
import "slices"
s := []int{3, 1, 2}
slices.Sort(s) // [1 2 3]
slices.SortFunc(s, cmp.Compare) // same for ordered types
i, ok := slices.BinarySearch(s, 2)
s2 := slices.Clone(s)
s = slices.Delete(s, 1, 2) // remove s[1]
s = slices.Compact(s) // adjacent dups (sorted first)
max := slices.Max(s)Useful helpers
| Func | Notes |
|---|---|
Contains / Index |
Linear search |
Compact / CompactFunc |
Needs sorted input for uniqueness |
Grow / Clip |
Capacity management |
Replace |
Splice |
Collect |
From iter.Seq (Go 1.23+) |
s = slices.DeleteFunc(s, func(n int) bool { return n%2 == 0 })maps
import "maps"
a := map[string]int{"x": 1, "y": 2}
b := maps.Clone(a)
maps.Copy(b, map[string]int{"y": 9, "z": 3})
eq := maps.Equal(a, b)
for k := range maps.Keys(a) { // Go 1.23+ iterators
_ = k
}maps.Keys / Values return iterators — collect with slices.Collect if you need a slice.
cmp
import "cmp"
cmp.Compare(a, b) // -1, 0, 1 for ordered types
cmp.Or(x, y, z) // first non-zero (useful defaults)
cmp.Less(a, b)slices.SortFunc(people, func(a, b Person) int {
if c := cmp.Compare(a.Last, b.Last); c != 0 {
return c
}
return cmp.Compare(a.First, b.First)
})iter and range-over-func
import "iter"
func Backward[E any](s []E) iter.Seq[E] {
return func(yield func(E) bool) {
for i := len(s) - 1; i >= 0; i-- {
if !yield(s[i]) {
return
}
}
}
}
for v := range Backward([]string{"a", "b", "c"}) {
fmt.Println(v)
}Pull-style when you need manual advancement:
next, stop := iter.Pull(Backward([]int{1, 2, 3}))
defer stop()
for {
v, ok := next()
if !ok {
break
}
fmt.Println(v)
}When not to use them
- Tiny one-off loops are fine as plain
for. - Do not force iterators everywhere — they shine for lazy pipelines and library APIs.
- Sorting huge slices of structs: consider indices or
sort.Slicepatterns if allocations dominate (benchmark).
Runnable example
go mod init example
go run .package main
import (
"cmp"
"fmt"
"iter"
"maps"
"slices"
)
func Countdown(n int) iter.Seq[int] {
return func(yield func(int) bool) {
for i := n; i >= 0; i-- {
if !yield(i) {
return
}
}
}
}
func main() {
s := []int{5, 1, 5, 3, 2}
slices.Sort(s)
fmt.Println("sorted", s)
fmt.Println("max", slices.Max(s))
s = slices.Compact(s)
fmt.Println("compact", s)
type pair struct{ K string; V int }
ps := []pair{{"b", 2}, {"a", 1}, {"a", 0}}
slices.SortFunc(ps, func(a, b pair) int {
if c := cmp.Compare(a.K, b.K); c != 0 {
return c
}
return cmp.Compare(a.V, b.V)
})
fmt.Println("pairs", ps)
m := map[string]int{"x": 1, "y": 2}
fmt.Println("clone equal?", maps.Equal(m, maps.Clone(m)))
fmt.Print("countdown:")
for v := range Countdown(3) {
fmt.Print(" ", v)
}
fmt.Println()
collected := slices.Collect(Countdown(2))
fmt.Println("collect", collected)
}Expected output:
sorted [1 2 3 5 5]
max 5
compact [1 2 3 5]
pairs [{a 0} {a 1} {b 2}]
clone equal? true
countdown: 3 2 1 0
collect [2 1 0]
What to notice: - Compact only removes adjacent duplicates — sort first for set-like uniqueness. - cmp.Compare composes clean multi-key sorts. - slices.Collect materializes a lazy iter.Seq.
Try next: Write Filter[T any](s []T, ok func(T) bool) iter.Seq[T] and range over it without allocating an intermediate slice.