Generics

Type parameters, constraints, generic functions, and generic data structures.

Advanced 35 min read 🐹 Go

Type Parameters

Go 1.18 added generics (type parameters). They let you write functions and types that work with any type while maintaining type safety:

// Before generics: separate functions for each type
func MinInt(a, b int) int { if a < b { return a }; return b }
func MinFloat(a, b float64) float64 { if a < b { return a }; return b }

// With generics: one function for all comparable types
func Min[T constraints.Ordered](a, b T) T {
    if a < b { return a }
    return b
}

fmt.Println(Min(3, 7))       // 3 (int)
fmt.Println(Min(3.14, 2.71)) // 2.71 (float64)
fmt.Println(Min("a", "b"))   // "a" (string)

Constraints

ConstraintAllows
anyAny type
comparableTypes supporting == and !=
constraints.OrderedTypes supporting < > <= >=
constraints.IntegerAll integer types

Generic Data Structures

type Stack[T any] struct {
    items []T
}

func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) }

func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 {
        var zero T
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

intStack := Stack[int]{}
intStack.Push(1)
intStack.Push(2)
val, _ := intStack.Pop() // 2
Key Takeaway: Use generics for data structures (Stack, Queue, Set) and utility functions (Min, Max, Contains, Filter). Don't use generics when interfaces work fine — keep it simple.

Practice Exercises

Hard Production Scenario

Design a solution using these concepts for a real-world production system.

Hard Performance Analysis

Benchmark two different approaches and explain which is better and why.