What are generics?
Generics allow you to write functions and types that work with multiple types, specified as type parameters, without sacrificing type safety.
Before generics, Go developers had to choose between code duplication (writing the same function for each type), type erasure using interface{} (now any) which loses type safety, or code generation to create type-specific code.
Example of the problem generics solve
// ❌ BAD: Code duplication
func IntMax(a, b int) int {
if a > b {
return a
}
return b
}
func Float64Max(a, b float64) float64 {
if a > b {
return a
}
return b
}
func StringMax(a, b string) string {
if a > b {
return a
}
return b
}
// ❌ BAD: Type erasure (loses type safety)
func Max(a, b interface{}) interface{} {
// Need runtime type checking, no compile-time safety
// ...
}
// ✅ GOOD: With generics
func Max[T comparable](a, b T) T {
if a > b {
return a
}
return b
}
Generics use type parameters—placeholders for types that are specified when the function or type is used. The compiler generates type-specific code for each type parameter used.
Basic syntax
// Generic function
func FunctionName[TypeParameter Constraint](param TypeParameter) ReturnType {
// ...
}
// Generic type
type TypeName[TypeParameter Constraint] struct {
field TypeParameter
}