๐ŸงฌGenericsLESSON

Generics

The problem generics solve

Before Go 1.18, writing a function that worked on multiple types meant one of two awkward choices: copy-paste the logic for each concrete type, or accept any (the empty interface) and sprinkle type assertions everywhere โ€” assertions that panic at runtime if the caller passes the wrong type.

Generics let you write one function that is type-safe and reusable across many types at once.

Generic function syntax

A generic function declares one or more type parameters in square brackets between the function name and its regular parameter list:

  • [T constraints.Ordered] โ€” the type parameter block; T is the name, constraints.Ordered is the constraint
  • a, b T โ€” both parameters use the same type T
  • The return type is also T

The compiler instantiates a concrete version of Min for each distinct type you call it with, so there is no runtime overhead from type dispatch.

Type constraints

A constraint specifies what operations are legal inside the function body. The three most common:

ConstraintMeaning
anyNo restrictions โ€” the type parameter can be anything
comparableSupports == and != (required for map keys)
constraints.OrderedSupports <, >, <=, >= โ€” covers integers, floats, strings

constraints.Ordered lives in the golang.org/x/exp/constraints package for Go 1.18โ€“1.20. Starting with Go 1.21 the standard library provides cmp.Ordered in the cmp package:

Multiple type parameters

You can declare more than one type parameter:

Generic higher-order functions

The compiler infers A and B from the arguments, so you rarely need to write them explicitly.

Generic types

Type parameters are not limited to functions โ€” you can parameterize a struct too:

Standard library generics (Go 1.21+)

Go 1.21 added generic helpers in the standard library:

When NOT to use generics

Generics are not always the right tool. Prefer a regular interface when:

  • You want runtime polymorphism on behavior โ€” e.g. io.Reader, fmt.Stringer
  • The abstraction has only one type involved (an interface is simpler)
  • The constraint would just be any and you immediately type-assert inside โ€” that's a sign you want an interface, not a type parameter

Use generics when:

  • You have algorithms or data structures whose logic is identical across types (Map, Filter, Stack)
  • You need the compiler to enforce type correctness across calls (e.g. a typed cache where the key and value types must match at compile time)

Knowledge Check

What syntax declares a generic function with a type parameter T?

Which constraint allows using < and > operators on a type parameter?

What does the `comparable` constraint enable?