The previous lesson hit a wall: a bare T can't be compared or printed. Trait bounds are how you tell the compiler 'this T has these capabilities' — and suddenly the generic code works.
Constraining a type parameter
fn largest<T: PartialOrd>(list: &[T]) -> &T says 'T must implement PartialOrd' — the trait behind the > and < operators. Now the body can compare values and the compiler accepts it. The bound is a promise: callers may only use types that satisfy it, and in exchange the body may use everything that trait provides.
Multiple bounds and where clauses
Stack bounds with +: T: Display + Clone means T must be both printable and cloneable. When the bounds pile up, a where clause moves them below the signature for readability — same meaning, cleaner to read when there are several type parameters each with several bounds.
T: Display reads 'whatever T is, it can be printed.' The bound is simultaneously a restriction on callers (only printable types allowed) and a permission for the body (you may print a T). That symmetry is the heart of generic Rust.impl Trait shorthand
For a single bound on a parameter, fn notify(item: &impl Summary) is shorthand for fn notify<T: Summary>(item: &T). It reads naturally — 'take anything that implements Summary.' Use it for simple cases; reach for the explicit <T> form when you need to name the type or reuse it across parameters.