Generics in Rust
Generics enable reusable code over types. The compiler monomorphizes generic code, generating optimized versions per concrete instantiation.
Type parameters and bounds
fn max<T: Ord>(a: T, b: T) -> T {
if a >= b { a } else { b }
}
Where clauses and multiple bounds
fn display_all<T>(xs: &[T])
where
T: std::fmt::Display + Clone,
{
for x in xs { println!("{x}"); }
}
Generic structs and impls
struct Pair<T> { a: T, b: T }
impl<T> Pair<T> {
fn new(a: T, b: T) -> Self { Self { a, b } }
}
Associated types vs generics in traits
Prefer associated types in traits for clearer relationships.
trait Storage {
type Item;
fn put(&mut self, item: Self::Item);
}
Default type params (in traits)
Libraries often provide defaults to reduce boilerplate in impls.
Zero‑cost abstractions
Monomorphization removes indirection; generic code is as fast as manual specializations.
PhantomData and variance (advanced)
Use PhantomData<T> to express ownership/lifetime relationships in zero‑sized types.
Summary
- Add type parameters with bounds; use
wherefor readability - Implement generic structs/impls; prefer associated types in traits
- Generics are zero‑cost via monomorphization