Generics
The problem generics solve
Before Go 1.18, writing a function that worked on multiple types meant one of two awkward choices: copy-paste the logic for each concrete type, or accept any (the empty interface) and sprinkle type assertions everywhere โ assertions that panic at runtime if the caller passes the wrong type.
Generics let you write one function that is type-safe and reusable across many types at once.
Generic function syntax
A generic function declares one or more type parameters in square brackets between the function name and its regular parameter list:
[T constraints.Ordered]โ the type parameter block;Tis the name,constraints.Orderedis the constrainta, b Tโ both parameters use the same typeT- The return type is also
T
The compiler instantiates a concrete version of Min for each distinct type you call it with, so there is no runtime overhead from type dispatch.
Type constraints
A constraint specifies what operations are legal inside the function body. The three most common:
| Constraint | Meaning |
|---|---|
any | No restrictions โ the type parameter can be anything |
comparable | Supports == and != (required for map keys) |
constraints.Ordered | Supports <, >, <=, >= โ covers integers, floats, strings |
constraints.Ordered lives in the golang.org/x/exp/constraints package for Go 1.18โ1.20. Starting with Go 1.21 the standard library provides cmp.Ordered in the cmp package:
Multiple type parameters
You can declare more than one type parameter:
Generic higher-order functions
The compiler infers A and B from the arguments, so you rarely need to write them explicitly.
Generic types
Type parameters are not limited to functions โ you can parameterize a struct too:
Standard library generics (Go 1.21+)
Go 1.21 added generic helpers in the standard library:
When NOT to use generics
Generics are not always the right tool. Prefer a regular interface when:
- You want runtime polymorphism on behavior โ e.g.
io.Reader,fmt.Stringer - The abstraction has only one type involved (an interface is simpler)
- The constraint would just be
anyand you immediately type-assert inside โ that's a sign you want an interface, not a type parameter
Use generics when:
- You have algorithms or data structures whose logic is identical across types (
Map,Filter,Stack) - You need the compiler to enforce type correctness across calls (e.g. a typed cache where the key and value types must match at compile time)
Knowledge Check
What syntax declares a generic function with a type parameter T?
Which constraint allows using < and > operators on a type parameter?
What does the `comparable` constraint enable?