Trait Bounds
A trait bound (T: Trait) restricts a generic type parameter so that only concrete types implementing Trait may be substituted for T, Simultaneously granting the generic body access to all methods, associated types, and associated constants of Trait.
Two Perspectives on a Trait Bound
A trait bound serves as a two-way compile-time contract between a function's caller and its implementation body:
Caller's Obligation Function Body's Guarantee
+-----------------------------+ +----------------------------------------+
| Concrete argument type MUST | | Body MAY ONLY call methods/items |
| implement `Trait` | <-> | declared on `Trait` (Checked once when |
| (Checked at every call site)| | the generic function is defined) |
+-----------------------------+ +----------------------------------------+
trait Validate {
fn is_valid(&self) -> bool;
fn validation_error(&self) -> &'static str;
}
struct PortNumber(u16);
impl Validate for PortNumber {
fn is_valid(&self) -> bool {
self.0 >= 1024
}
fn validation_error(&self) -> &'static str {
"port must be an unprivileged port (>= 1024)"
}
}
fn ensure_valid<T: Validate>(item: &T) -> Result<(), &'static str> {
if item.is_valid() {
Ok(())
} else {
Err(item.validation_error())
}
}
fn main() {
println!("8080: {:?}", ensure_valid(&PortNumber(8080)));
println!("80: {:?}", ensure_valid(&PortNumber(80)));
}
8080: Ok(())
80: Err("port must be an unprivileged port (>= 1024)")
Passing a Type That Does Not Satisfy the Bound (E0277)
If a caller passes a type that does not implement the required trait, rustc rejects the call site with error E0277 and points directly to the trait bound that was violated:
// ❌ does not compile
trait Validate {
fn is_valid(&self) -> bool;
}
fn check<T: Validate>(item: &T) -> bool {
item.is_valid()
}
struct UncheckedInput;
fn main() {
let input = UncheckedInput;
check(&input);
}
error[E0277]: the trait bound `UncheckedInput: Validate` is not satisfied
--> src/main.rs:14:11
|
14 | check(&input);
| ----- ^^^^^^ the trait `Validate` is not implemented for `UncheckedInput`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check`
--> src/main.rs:6:13
|
6 | fn check<T: Validate>(item: &T) -> bool {
| ^^^^^^^^ required by this bound in `check`
Conditional Method Availability via Trait Bounds
Trait bounds on impl<T: Bound> Type<T> allow wrapper and collection types to expose methods only when their inner element type supports the underlying capability. For example, Vec<T> implements Clone only when T: Clone:
struct BoxedValue<T> {
value: T,
}
impl<T> BoxedValue<T> {
fn new(value: T) -> Self {
Self { value }
}
}
impl<T: PartialEq> BoxedValue<T> {
fn matches(&self, expected: &T) -> bool {
&self.value == expected
}
}
fn main() {
let v = BoxedValue::new(42);
println!("Matches 42: {}", v.matches(&42));
}
Matches 42: true
Trait Bounds on Associated Types
A trait bound can also constrain an associated type of a trait using equality (I: Iterator<Item = u32>) or nested trait bounds (I: Iterator, I::Item: Display):
use std::fmt::Display;
fn print_all<I>(iter: I)
where
I: IntoIterator,
I::Item: Display,
{
for (idx, item) in iter.into_iter().enumerate() {
println!("[{idx}] {item}");
}
}
fn main() {
print_all(["alpha", "beta", "gamma"]);
}
[0] alpha
[1] beta
[2] gamma