Lesson 10 / 26

Generics

Type parameters and constraints.

Write once for many types

Since Go 1.18, functions and types can take type parameters: func Max[T cmp.Ordered](items []T) T works for any ordered type. Constraints (interfaces such as any, comparable, cmp.Ordered) say what operations are allowed. Generic types like Stack[T] hold any element type. Use generics for containers and algorithms over many types (the slices and maps packages are generic); prefer interfaces when you need behaviour rather than type-agnostic data handling.

Generic functions and a generic stack, run

I ran this with Go 1.27.1 (go run . in a module named demo, standard library only). Max works for ints and strings, Map converts ints to strings, and Stack[T] returns the zero value and false when empty.

package main

import (
	"cmp"
	"fmt"
)

func Max[T cmp.Ordered](items []T) T {
	m := items[0]
	for _, v := range items[1:] {
		if v > m {
			m = v
		}
	}
	return m
}

func Map[T, U any](in []T, f func(T) U) []U {
	out := make([]U, 0, len(in))
	for _, v := range in {
		out = append(out, f(v))
	}
	return out
}

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
	}
	v := s.items[len(s.items)-1]
	s.items = s.items[:len(s.items)-1]
	return v, true
}

func main() {
	fmt.Println(Max([]int{3, 9, 4}), Max([]string{"kiwi", "apple", "mango"}))
	fmt.Println(Map([]int{1, 2, 3}, func(n int) string { return fmt.Sprint(n * n) }))
	var s Stack[string]
	s.Push("a"); s.Push("b")
	v, _ := s.Pop()
	_, ok := (&Stack[int]{}).Pop()
	fmt.Println(v, ok)
}

Output:

9 mango
[1 4 9]
b false

Reach for slices and maps packages first

Many generic helpers (Contains, Index, Sort, Max, Keys) already exist in the standard library.

Quick check: What does the constraint cmp.Ordered allow?

  • Types that support < and > comparisons
  • Any type at all
  • Only strings
  • Only types with a String method
Answer

Types that support < and > comparisons — Constraints limit type parameters.