What are Go generics and how do type parameters and constraints work?
Learn how Go generics work: declaring type parameters, writing constraints with type sets and the ~ token, and why they beat interface{} for reusable code.
Expected Interview Answer
Go generics, added in Go 1.18, let you write functions and types parameterized by type parameters, so one implementation works for many concrete types while staying fully type-safe. Constraints are interfaces that limit which types a type parameter may accept.
A type parameter is declared in square brackets, e.g. func Max[T constraints.Ordered](a, b T) T. The constraint (an interface) defines the operations allowed on T — either a method set or, using type sets with the ~ token and union operators, a set of underlying types. The compiler shapes the generic code per type, so there are no runtime type assertions or reflection, unlike the old interface{}-plus-cast approach.
- Reusable code without duplicating per type
- Compile-time type safety, no runtime casts
- Cleaner than interface{} and reflection
- Type sets express allowed underlying types
- Better performance than boxing into any
AI Mentor Explanation
A type parameter is a batting-order slot that any specified player can fill; the constraint is the eligibility rule — only players who can bat right-handed, say — so the slot works for many players yet still enforces who qualifies.
Step-by-Step Explanation
Step 1
Declare type parameters
Add a bracketed list after the name: func Map[T, U any](s []T, f func(T) U) []U.
Step 2
Choose a constraint
Use any for no restriction, or a constraint interface like constraints.Ordered or comparable.
Step 3
Define type sets
Write custom constraints with unions and the ~ token, e.g. ~int | ~float64, to allow underlying types.
Step 4
Use allowed operations
Inside the body, only operations permitted by the constraint (methods or operators) are valid on T.
Step 5
Instantiate
Call with explicit types Max[int](1, 2) or let the compiler infer them from the arguments.
What Interviewer Expects
- Type parameters declared in square brackets
- Constraints as interfaces limiting allowed types
- Type sets with ~ and union operators
- comparable and any as built-in constraints
- Why generics beat interface{} plus casting
Common Mistakes
- Confusing constraints with regular interface values
- Forgetting ~ so named types with the underlying type fail
- Overusing generics where an interface is simpler
- Assuming generics rely on runtime reflection
- Using operators not permitted by the constraint
Best Answer (HR Friendly)
“Go generics let you write one function or data structure that works with many different data types instead of copying it for each type. You attach a rule, called a constraint, that says which types are allowed, and the compiler checks everything up front so the code stays safe and fast.”
Code Example
package main
import "fmt"
// Number is a constraint: a type set of underlying numeric types.
type Number interface {
~int | ~int64 | ~float64
}
// Sum works for any type satisfying Number.
func Sum[T Number](nums []T) T {
var total T
for _, n := range nums {
total += n // + is allowed because every type in the set supports it
}
return total
}
func main() {
fmt.Println(Sum([]int{1, 2, 3})) // inferred T = int
fmt.Println(Sum([]float64{1.5, 2.5})) // inferred T = float64
}Follow-up Questions
- What is the difference between any and comparable constraints?
- What does the ~ token mean in a constraint?
- When should you prefer an interface over generics?
- How does the compiler infer type arguments?
- Can methods have their own type parameters in Go?
MCQ Practice
1. What is a constraint in Go generics?
Constraints are interfaces (often type sets) that define which types and operations a type parameter permits, enforced at compile time.
2. What does ~int mean inside a constraint?
The ~ token matches any type whose underlying type is int, including named types like type Celsius int.
Flash Cards
Type parameter — A placeholder type declared in square brackets, e.g. func F[T any](x T).
Constraint — An interface limiting which types a type parameter accepts and what operations are allowed.
Type set (~ and |) — A constraint listing allowed underlying types, e.g. ~int | ~float64, using the ~ and union operators.
comparable — Built-in constraint for types usable with == and !=, e.g. as map keys.
Why not interface{}? — Generics keep compile-time type safety and avoid runtime casts and reflection.
Continue Learning
Related Interview Questions
What are Go interfaces and how does implicit implementation work?
medium
What is the empty interface (interface{} / any) in Go and when is it used?
medium
How does error handling work in Go and why does it not use exceptions?
medium
How does the underlying array, length, and capacity of a Go slice work?
medium