GGistDev

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 where for readability
  • Implement generic structs/impls; prefer associated types in traits
  • Generics are zero‑cost via monomorphization