slices, maps, cmp, and iter

Updated

September 8, 2026

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.Slice patterns 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.