08 — Generics
Writing one function that works for many types without losing type safety: type parameters and constraints. Every example is live — edit it and press Run.
Type parameters and constraints
A type parameter is a placeholder type in square brackets after the function name. The compiler fills it in per call (usually inferred, so you call it like an ordinary function) and type-checks each use. A constraint says which operations are allowed:
any— no assumptions, only move values around (Map,Filter);comparable— permits==/!=(map keys);cmp.Ordered— permits<,>for numbers and strings (Max).
package main
import (
"cmp"
"fmt"
"strconv"
)
func Map[T, U any](in []T, f func(T) U) []U {
out := make([]U, len(in))
for i, x := range in {
out[i] = f(x)
}
return out
}
func Filter[T any](in []T, keep func(T) bool) []T {
var out []T
for _, x := range in {
if keep(x) {
out = append(out, x)
}
}
return out
}
func Max[T cmp.Ordered](xs []T) (T, bool) {
if len(xs) == 0 {
var zero T
return zero, false
}
m := xs[0]
for _, x := range xs[1:] {
if x > m { // allowed because T is cmp.Ordered
m = x
}
}
return m, true
}
func main() {
fmt.Println(Map([]int{1, 2, 3}, func(x int) int { return x * 2 }))
fmt.Println(Map([]int{1, 2, 3}, strconv.Itoa)) // T=int, U=string
fmt.Println(Filter([]int{1, 2, 3, 4, 5, 6}, func(x int) bool { return x%2 == 0 }))
fmt.Println(Max([]int{3, 7, 2, 9, 4}))
fmt.Println(Max([]string{"apple", "cherry", "banana"}))
}
Output:
[2 4 6]
[1 2 3]
[2 4 6]
9 true
cherry true
One Max works for []int, []string,
[]float64 — one implementation, checked per type. var zero T
gives the zero value for whatever T turns out to be. Go generics compile to
code on the real types (closer to C++ templates than to a void *
container), so there's no boxing in the common case.
Recap
| Concept | In Go |
|---|---|
| Type parameter | func F[T any](...) |
| Calling | Type args inferred: Map(xs, f) |
any | Any type; move values only |
comparable | Permits == / != |
cmp.Ordered | Permits <, > (numbers, strings) |
Next: 09 — io.Reader & io.Writer.