Why Generics Matter

Overview

Generics (type parameters), introduced in Go 1.18, allow writing functions and types that work with multiple types while maintaining type safety.

The Problem Before Generics

// Without generics: duplicate code or use interface{}
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
}

// Or lose type safety
func Min(a, b interface{}) interface{} {
    // Requires type assertions, runtime checks
}

With Generics

func Min[T constraints.Ordered](a, b T) T {
    if a < b {
        return a
    }
    return b
}

Min(1, 2)         // int
Min(1.5, 2.5)     // float64
Min("a", "b")     // string

Type Parameters

func Print[T any](v T) {
    fmt.Println(v)
}

// Multiple type parameters
func Pair[K, V any](k K, v V) (K, V) {
    return k, v
}

Constraints

import "golang.org/x/exp/constraints"

// Built-in constraints
any           // No requirements
comparable    // Supports == and !=

// From constraints package
constraints.Ordered    // Supports < > <= >=
constraints.Integer    // Int types
constraints.Float      // Float types

Custom Constraints

type Number interface {
    int | int32 | int64 | float32 | float64
}

func Sum[T Number](nums []T) T {
    var total T
    for _, n := range nums {
        total += n
    }
    return total
}

Generic Type Aliases (Go 1.24+)

Go 1.24 introduced support for generic type aliases, allowing you to create aliases for generic types.

type Set[T comparable] map[T]struct{}

// Type alias (Go 1.24+)
type IntSet = Set[int]
type AnySet[T comparable] = Set[T]

This is particularly useful for refactoring and maintaining compatibility while migrating to generic implementations.

Benefits

  1. Type safety: Errors caught at compile time
  2. No code duplication: One implementation for many types
  3. Performance: No interface boxing/unboxing
  4. Better documentation: Types are explicit

Summary

Before After
Code duplication Single generic function
interface{} Type parameters
Runtime errors Compile-time errors
Type assertions Direct usage