On this page
Generics and Monomorphization
The core mechanism of Rust generics is monomorphization—the compiler generates independent machine code for each concrete type parameter at compile time. This means
Vec<i32>andVec<String>are two completely separate function bodies, with zero runtime overhead, at the cost of binary bloat. const generics also incorporate constant values into generic parameters, while specialization allows providing better implementations for specific types (currently nightly only).
Monomorphization: Generating Code for Each Concrete Type at Compile Time
Rust generics do not use runtime polymorphism (no vtables)—the compiler generates independent machine code for each concrete type used with generics:
let _ = max; // Compiler generates max_i32
let _ = max; // Compiler generates max_f64
let x = "a"; let y = "b";
let _ = max; // Compiler generates max_&str
// The output binary contains 3 independent max functions, each optimized for a specific type
This is the same mechanism as C++ templates—both generate code at compile time. However, in Rust, generics are checked at definition time (no need to wait for instantiation), so error messages are clearer. C++ template errors usually appear at instantiation, leading to dozens of lines of template error output.
The Meaning of "Zero-Cost Abstraction"
In release builds, generic functions are usually inlined at the call site—in the final assembly, the generic function itself disappears, leaving only a few cmp instructions that directly operate on i32 or f64. This is what Rust calls "zero-cost abstraction": you can use high-level abstractions, but the compiled code is as fast as hand-written code for specific types.
Code Bloat and Mitigation
Generating code for each concrete type → many type combinations → explosion in compile time + binary size. A classic mitigation strategy: extract non-generic inner functions:
// Does not depend on T → no branching
Key point: Separate the parts that must be generic (type conversion) from the parts that can be handled with trait objects or concrete types (business logic).
Const Generics: Values as Generic Parameters
Traditional generic parameters are types. const generics (Rust 1.51+) allow values to also be generic parameters—compile-time constants:
let b1: = Buffer ;
let b2: = Buffer ;
// b1 and b2 are **different types**! They cannot be assigned to each other
Main use cases: fixed-size arrays/vectors, SIMD lanes, compile-time assertion of array size.
Specialization (nightly, not yet stable)
Current stable Rust does not support trait specialization—you cannot provide a "more specific impl that overrides a more general impl" for a trait. This limits certain performance optimizations (e.g., providing a more efficient Extend impl for Vec<u8> than for generic Vec<T>). min_specialization is available on nightly, but not yet on stable. The current workaround is to use the newtype pattern to provide specialization.
References
- Rust Book: Chapter 10.1
- Rust Reference: Const generics
- RFC 2000: Const generics; RFC 1210: Specialization
Keywords: monomorphization, zero-cost abstraction, code bloat, const generics, specialization