Type Constraints
In this page:
Defining a Constraint Interface
A type constraint is written as an interface, and a generic function's type parameter references it to limit which concrete types are legal -- restricting the operations available inside the function to what the constraint guarantees.
Example: Defining a Constraint Interface
package main
import "fmt"
type Ordered interface {
int | int64 | float64 | string
}
func Max[T Ordered](a, b T) T {
if a > b {
return a
}
return b
}
func main() {
fmt.Println(Max(3, 9))
fmt.Println(Max("apple", "banana"))
}
Login to try C/C++/Java/PHP code in the editor
Constraints with Method Requirements
Like a normal interface, a constraint can require specific methods rather than (or in addition to) a union of allowed types, letting generic code call those methods on any value of the type parameter.
Example: Constraints with Method Requirements
package main
import "fmt"
type Stringer interface {
String() string
}
func PrintAll[T Stringer](items []T) {
for _, item := range items {
fmt.Println(item.String())
}
}
type Item struct {
Name string
}
func (i Item) String() string { return "Item: " + i.Name }
func main() {
PrintAll([]Item{{Name: "Pen"}, {Name: "Book"}})
}
Login to try C/C++/Java/PHP code in the editor
Combining Unions and Methods
A constraint interface can combine a type union with method requirements, giving fine-grained control over exactly which types are acceptable and what operations the generic code may perform on them.
Example: Combining Unions and Methods
package main
import "fmt"
type Numeric interface {
~int | ~float64
}
func Average[T Numeric](nums []T) float64 {
var total T
for _, n := range nums {
total += n
}
return float64(total) / float64(len(nums))
}
func main() {
fmt.Println(Average([]int{2, 4, 6}))
}
Login to try C/C++/Java/PHP code in the editor
- Defining a constraint interface but forgetting a union of types (int | float64) is what actually allows arithmetic operators, not method requirements alone.
- Trying to use a struct's own methods as an implicit constraint without explicitly declaring an interface listing them.
- Overcomplicating a constraint when the built-in any or the standard library's constraints/cmp package already covers the need.
- A constraint is an interface that limits which types can be substituted for a type parameter.
- A union of types, like int | float64, is used in a constraint to allow operators such as + or <.
- The built-in comparable constraint allows == and != on a type parameter.
- Constraints can also require specific methods, just like any regular interface.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: