Stage 1 · Code
Generics
Type Constraints
Understand why `any` is often too loose, then learn how constraints tell the compiler exactly which operations a generic function is allowed to perform.
Why any Is Not Enough
Imagine hiring someone with one requirement: 'must be a person.' That rule is technically broad enough to accept everyone, but it tells you nothing about whether they can weld, teach, or drive a forklift. The rule is too loose for the job you actually need done.
any plays that same role in generics. It says T can be any type at all. That is fine when your function only stores values, returns them, or moves them around unchanged. But the moment your function wants to compare with < or add with +, the compiler needs stronger promises.
That is the heart of type constraints. A constraint is how you tell the compiler, 'this function is generic, but not infinitely generic. It only works for types that support the operations I need.'
comparable Means Equality Is Safe
Some operations have a natural built-in rule. Equality with == is one of them. Go gives you the comparable constraint for exactly this case.
Custom Constraints
Built-in constraints are helpful, but real work often needs a more specific family of types. For example, if you want to add values with +, you probably want a numeric set of types, not literally every comparable type in Go.
That | symbol means 'or.' So ~int | ~int64 | ~float64 means: any type whose underlying type is int, or int64, or float64.
Why the Tilde Matters
The ~ operator is easy to skip over, but it matters a lot. It means 'not just this exact built-in type, but also named types whose underlying type is this built-in type.'
This is a very common beginner surprise. A named type like type Score int is not identical to int, even though its underlying representation is the same. ~int is what widens the door to include it.
Ordered and the cmp Package
When your generic code needs ordering operators like <, <=, >, or >=, the most common reusable rule is 'ordered types.' Older material online often references golang.org/x/exp/constraints.Ordered, but in newer Go versions you can use cmp.Ordered from the standard library.
Tracing a Constrained Call
Let's trace a call where the ~ operator is doing real work. This will show you why custom constraints are more than just syntax trivia.
Quiz
Why is `T any` not enough for a function that wants to use `<`?
Practice
Write a generic function `CountOccurrences[T comparable](items []T, target T) int` that counts how many times `target` appears in the slice.
Summary
- Constraints tell the compiler what operations a generic function is allowed to use safely.
anyis fine for pass-through behavior, but too loose for arithmetic, equality, or ordering rules.comparablemeans==and!=are safe.- Custom constraints use type sets to describe a family of allowed concrete types.
~includes named types with a matching underlying type, which is often what makes a constraint useful in real code.- For ordered values, newer Go versions provide
cmp.Orderedin the standard library.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.