Generic Algorithms: slices, maps & cmp Packages
Go 1.21 added slices, maps, and cmp - generic-first stdlib packages for sorting, searching, cloning, and three-way comparison.
Use them before custom helpers; extend with your own generics only for domain logic they do not cover.
Summary
slices operates on []E with constraints like cmp.Ordered or comparable.
maps provides copy, delete, and equality for map[K]V.
cmp defines Ordered, Compare, and Or for building constraints and comparers.
Custom algorithms follow the same patterns: one type parameter for elements, separate parameters for keys and values when needed.
Recipe
Quick-reference recipe card - copy-paste ready.
import (
"cmp"
"slices"
)
func TopN[T cmp.Ordered](data []T, n int) []T {
if n <= 0 {
return nil
}
cp := slices.Clone(data)
slices.Sort(cp)
if n > len(cp) {
n = len(cp)
}
return cp[len(cp)-n:]
}When to reach for this:
- Sorting, binary search, compact, insert, delete on slices.
- Cloning or merging maps without manual loops.
- Building constraints with
cmp.Orderedinstead of copying large unions.
Working Example
package main
import (
"cmp"
"fmt"
"maps"
"slices"
)
type User struct {
Name string
Age int
}
func main() {
nums := []int{3, 1, 4, 1, 5}
slices.Sort(nums)
fmt.Println(nums)
fmt.Println(slices.BinarySearch(nums, 4))
m1 := map[string]int{"a": 1, "b": 2}
m2 := maps.Clone(m1)
m2["c"] = 3
fmt.Println(maps.Equal(m1, m2))
users := []User{{"ann", 30}, {"bob", 25}}
slices.SortFunc(users, func(a, b User) int {
return cmp.Compare(a.Age, b.Age)
})
fmt.Println(users)
}What this demonstrates:
slices.Sortrequires ordered elements;SortFuncaccepts custom comparers returningcmpsign.maps.Cloneandmaps.Equalavoid hand-rolled copy/equality.- Struct sorting uses
cmp.Compareon fields, not==on structs unless fully comparable and that is the intended order.
Deep Dive
How It Works
- Stdlib generic functions are implemented once in the library and monomorphized at your call sites.
slicesfunctions mutate slices in place unless the name saysCloneor returns a new slice.mapsfunctions do not deep-copy values; pointers and slices inside values alias like ordinary map assignment.cmp.Comparereturns -1, 0, or 1 for ordered types and is the preferred comparer return type forslices.SortFunc.
slices Highlights
| Function | Purpose |
|---|---|
Sort, SortFunc | In-place sort |
BinarySearch, BinarySearchFunc | Search sorted slice |
Contains, Index | Linear search |
Clone, Compact, Delete | Slice memory operations |
Insert, Replace | Structural edits |
maps Highlights
| Function | Purpose |
|---|---|
Clone | Shallow copy of map |
Copy | Merge into destination |
Equal | Deep equality of keys and values |
DeleteFunc | Remove by predicate |
cmp Highlights
| Symbol | Purpose |
|---|---|
cmp.Ordered | Constraint for ordered built-ins and underlying types |
cmp.Compare(x, y) | Three-way compare for ordered types |
cmp.Or(x, y, …) | Pick first non-zero compare result in sort keys |
Go Notes
// Multi-key sort with cmp.Or
slices.SortFunc(records, func(a, b Record) int {
return cmp.Or(
cmp.Compare(a.Region, b.Region),
cmp.Compare(a.Name, b.Name),
)
})- Prefer
slices.SortFuncoversort.Slicefor new code - clearer comparer signatures. - For stable sort requirements, check whether
slices.SortStableFuncfits your Go version and use it when equal elements must keep input order. - Custom generic
Maptransforms are still useful:func Map[T, U any](in []T, f func(T) U) []U.
Gotchas
- Sorting with
==on structs - UseSortFuncwith explicit field order. Fix:cmp.Oron fields. - Assuming
maps.Clonedeep-copies - Values alias. Fix: clone nested structures explicitly when needed. - Binary search on unsorted slice - Undefined position results. Fix: sort first or document precondition.
- Reusing union constraints locally - Drift from stdlib. Fix: import
cmp.Ordered. - Mutating slice during range in custom algorithm - Skips elements or races. Fix: index-based loops or collect indices first.
- Passing nil map to
maps.Copy- Panic on write to nil map. Fix:dst = make(map[K]V)before copy.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
sort package | Legacy code, non-slice types | New slice-only code |
| Hand-written loops | Tiny one-off in hot path already inlined | Repeated algorithm across types |
x/exp/slices experiments | Bleeding-edge features | Production without vetting |
| Domain-specific tree/index | Order statistics beyond slice sort | Simple in-memory batches |
FAQs
When should I import slices instead of writing Contains?
Always for production maintenance - stdlib tracks Go releases and optimizations.
Custom generics for one-liners rarely pay off.
What is the difference between Sort and SortFunc?
Sort needs cmp.Ordered elements.
SortFunc accepts any element type with a comparer function.
Does slices.Clone allocate?
Yes - new backing array.
Use when you must detach from caller memory.
How does maps.Equal treat nil maps?
Two nil maps are equal.
Nil vs empty non-nil map are not equal.
What does cmp.Or do?
Returns the first non-zero comparison in a chain.
Ideal for lexicographic multi-field sorts.
Can I use slices on []byte?
byte is ordered.
Sort works; remember bytes package also has specialized helpers.
Are these packages available on TinyGo?
Support varies by version and board.
Verify in CI for embedded targets.
How do I write Map/filter in generics?
Simple Map with []T to []U is a few lines.
Filter returns clipped slice or append to preallocated buffer.
Is BinarySearch stable for duplicates?
It finds any matching index in sorted data.
Walk neighbors if you need all equal elements.
Should HTTP middleware use slices helpers?
Yes for header lists, allowed methods, and path segment sorting in tests.
Keep handler signatures non-generic.
Do generics algorithms inline?
Small monomorphized bodies often inline like hand-written code.
Benchmark if doubtful.
What replaces sort.Slice in new code?
slices.SortFunc with cmp.Compare or cmp.Or comparers.
Related
- Generics Basics -
slices.Containsintro - Type Parameters & Constraint Interfaces -
cmp.Ordereddefinition - Type Sets & the comparable Constraint -
maps.Equalvs== - Generic Data Structures: Sets, Queues, Maps - containers using these helpers
- Performance Implications of Generics - sort cost and inlining
Stack 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).