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.