Skip to main content

Generics and trait bounds

A generic parameter `T` stands for a type the caller chooses. On its own the compiler knows nothing about `T`, so you add trait bounds to say what it must be able to do — `T: PartialOrd` for comparison, `T: Display` for printing.

Generics are monomorphised: the compiler stamps out a specialised copy for each concrete type actually used. There is no boxing, no vtable and no runtime cost compared with writing the versions by hand.

`where` clauses say the same thing with more room to breathe once the bounds get long.

Using an operator without a bound

fn largest<T>(items: &[T]) -> &T {
    let mut best = &items[0];
    for item in items {
        if item > best { best = item; } // error[E0369]
    }
    best
}

error[E0369]: binary operation `>` cannot be applied to type `&T`

Tell the compiler what `T` can do: `fn largest<T: PartialOrd>(...)`. Without a bound, a generic type supports nothing at all.

Run it and change it

The editor below is live: edit anything and the real compiler output updates by itself.

Your Rust