← Back to Go Course | Chapter 12: Generics | Lesson 5 of 6

Type Constraints

A constraint is a rule that says 'you can use any type here, as long as it can do these specific things', like requiring every recipe ingredient to at least be edible.
Syntax
go
type Constraint interface {
    ~int | ~float64 | string
}

func Name[T Constraint](param T) T {
    // body
}

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

markup
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"))
}

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

markup
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"}})
}

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

markup
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}))
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Defining a constraint interface but forgetting a union of types (int | float64) is what actually allows arithmetic operators, not method requirements alone.
  2. Trying to use a struct's own methods as an implicit constraint without explicitly declaring an interface listing them.
  3. Overcomplicating a constraint when the built-in any or the standard library's constraints/cmp package already covers the need.
Chapter Summary
  • 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:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.