Stage 1 · Code
Generics
Why Generics?
See the exact hole generics were added to fill in Go: duplicated functions everywhere, or flexible but fragile `interface{}` code that pushes mistakes to runtime.
The Same Job Over and Over
Imagine you run a warehouse and keep buying separate clipboards for the exact same checklist: one clipboard for blue boxes, one for red boxes, one for green boxes. The checklist itself never changes. Only the label at the top changes. After a while, that starts to feel silly.
That was a real pain in Go before generics arrived in Go 1.18. You would write one function for []int, then another nearly identical one for []float64, then another for some named numeric type. The computer was happy, but the human maintaining the code paid the price.
So before we talk about syntax, stop on the human problem first: sometimes you have one idea, one algorithm, one exact loop — but you want to reuse it with several different concrete types without copy-pasting the logic.
The core problem is not 'I want fancy syntax.' The core problem is 'I have one piece of logic that should work for a family of types, and I want the compiler to still protect me.'
The Two Old Options
Before generics, you usually had two choices. Neither was great in every situation.
| Option | What you gained | What you paid |
|---|---|---|
| Duplicate functions | Simple, type-safe code | You repeat the same logic for every type |
interface{} or any | One flexible function | You lose compile-time type safety and must inspect types at runtime |
That duplication may look harmless with two functions. But real codebases do not stop at two. The cost grows quietly: more functions to name, more tests to keep in sync, more places to update when the logic changes.
Notice the tradeoff clearly. The duplicated version is safe but repetitive. The interface{} version is reusable but fragile. You can no longer tell, just by looking at the function signature, what kinds of values are actually valid.
One Function, Many Concrete Types
Generics give Go a third option: write the logic once, tell the compiler what family of types is allowed, and keep type checking at compile time instead of postponing it to runtime.
This is the big win in plain language: you stop choosing between repetition and runtime guessing. Generics let you keep one copy of the idea without giving up the compiler's help.
Reading the Generic Version
Only now is the formal vocabulary useful. The T inside square brackets is a type parameter. You can read it as, 'this function works with some type T, as long as T fits the Number rule.'
func Sum[T Number]declares a function with a type parameter namedT.T NumbermeansTis not totally unconstrained — it must be one of the numeric types allowed byNumber.nums []Tmeans the function accepts a slice whose element type is that sameT.- The return type is also
T, so[]intproduces anint, and[]float64produces afloat64.
A generic function is not 'untyped.' It is more like a reusable blueprint. Each call still has a real concrete type, and the compiler checks that concrete type against the function's rules.
Tracing a Real Call
Let's slow the generic version down and watch one real call happen. We are not tracing an abstract T in the air. We are tracing actual values.
Quiz
What real problem are generics solving in the `Sum` example?
Practice
Time to write a tiny generic function yourself. The goal is the same as this lesson's main idea: one simple behavior, reusable for many concrete types.
Write a generic function `Last[T any](items []T) (T, bool)` that returns the final element of a slice and `true`. If the slice is empty, return the zero value of `T` and `false`.
Summary
- Before generics, Go often forced you to choose between duplicated functions and
interface{}-based runtime guessing. - Generics let you write one algorithm for a family of types while keeping compile-time checking.
- A generic function is still used with real concrete types at each call site.
func Sum[T Number](nums []T) Tmeans: one reusable function, but only for types that satisfy theNumberrule.- The value of generics is not novelty — it is safer reuse with less repetition.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.