Frontend Labs
⋯

21. Generics: type parameters and constraints

21.1 The problem generics solve

Before Go 1.18, a generic-shaped function like "sum any slice of numbers" required either code generation, interface{} plus reflection (slow, unsafe at compile time), or a copy-pasted function per type. Generics add compile-time-checked type parameters:

func Sum[T int | int64 | float64](nums []T) T {
	var total T
	for _, n := range nums {
		total += n
	}
	return total
}

Sum([]int{1, 2, 3})          // T inferred as int
Sum([]float64{1.5, 2.5})     // T inferred as float64

21.2 Constraints

T int | int64 | float64 is an inline type set constraint. The standard library's golang.org/x/exp/constraints (and the built-in cmp.Ordered in modern Go) name common ones:

import "cmp"

func Max[T cmp.Ordered](a, b T) T {
	if a > b {
		return a
	}
	return b
}

any is the loosest constraint (no operations allowed beyond assignment and comparison-to-nil for interface types); a constraint like comparable permits ==/!=, which is what makes a generic map key type possible.

21.3 A generic data structure

type Stack[T any] struct {
	items []T
}

func (s *Stack[T]) Push(v T) {
	s.items = append(s.items, v)
}

func (s *Stack[T]) Pop() (T, bool) {
	var zero T
	if len(s.items) == 0 {
		return zero, false
	}
	last := s.items[len(s.items)-1]
	s.items = s.items[:len(s.items)-1]
	return last, true
}

intStack := &Stack[int]{}
intStack.Push(1)
intStack.Push(2)
v, _ := intStack.Pop() // v == 2

21.4 When not to reach for generics

If an interface with one or two methods already expresses what you need (Chapter 9), prefer it — generics shine for data structures and algorithms parameterized purely by type (a generic Stack[T], a generic Map/Filter/Reduce over slices), not as a default replacement for interfaces or as a way to avoid writing two similar 5-line functions.

21.5 Real-world example

A generic LRU cache — Cache[K comparable, V any] — is strictly better than the map[string]*Node version from projects/lru_cache.md: the same code now works for Cache[int, User] or Cache[string, []byte] with zero duplication and full compile-time type safety. Chapter 26 builds this version.


Generated from real-life-golang-guide.md · 8 Oct 2026 16:36