Trait Bounds
Bounds constrain generic parameters so code can call trait methods safely: T: Display, where clauses, and multiple bounds with +.
Recipe
use std::fmt::Display;
fn print_all<T: Display>(items: &[T]) {
for item in items {
println!("{item}");
}
}
fn compare<T>(a: T, b: T) -> T
where
T: PartialOrd,
{
if a > b { a } else { b }
}When to reach for this: Any generic function using trait methods; prefer where for readable complex bounds.
Working Example
use std::fmt::{Debug, Display};
fn report<T>(value: T) -> String
where
T: Debug + Display,
{
format!("user sees {value}, debug {value:?}")
}
fn main() {
println!("{}", report(42));
}What this demonstrates:
- Multiple bounds
Debug + Display whereclause separates bounds from signature- Bounds checked at compile time per monomorphized
T - Violation fails at call site with clear error
Deep Dive
impl Trait sugar
fn f(x: impl Display) == fn f<T: Display>(x: T) for one parameter.
Higher-ranked bounds
for<'a> for fns needing any lifetime - advanced with Fn traits.
Lifetime bounds
T: 'a - values in T cannot borrow shorter than 'a.
Gotchas
- Bound too weak - Missing method on
T. Fix: Add trait to bound list. - Bound too strong - Limits usable types. Fix: Split functions or use trait objects.
- Conflicting blanket impls - Two overlapping auto impls. Fix: Avoid impossible blanket patterns.
whereclause explosion - Unreadable. Fix: Type aliasestype SerializeMap = ....impl Traitin return not object-safe mix - Cannot return differentimpl Traittypes. Fix: Enum orBox<dyn Trait>.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
dyn Trait parameter | Heterogeneous inputs | Generics faster |
| Concrete types | Single use | Library reuse |
| Enum of capabilities | Closed options | Open trait set |
| Macros | Generate bounded fns | Bounds expressible |
FAQs
`where` vs inline bounds?
Style - `where` cleaner for long lists.Bound on associated type?
`where T::Item: Clone`.Impl Trait multiple?
`impl A + B` in parameters.Negative bounds?
Not supported - use sealed traits or separate types.Auto traits?
`Send`, `Sync` automatically implemented when safe.Trait alias?
`trait MyBound = A + B + C;` stable feature.Bounds in structs?
`struct S<T: Display>(T)`.Relax bounds?
Split API: less bounded helper + thin wrapper.GAT bounds?
Generic associated types carry own bounds.async bounds?
`T: Future` or `T: AsyncRead` etc.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.