Multiple Trait Bounds
A multiple trait bound (T: TraitA + TraitB) requires a generic type parameter to implement every trait in a +-separated list simultaneously.
Combining Traits with the + Operator
Inside a function or impl block where T: TraitA + TraitB is declared, values of type T can call methods from both TraitA and TraitB:
use std::fmt::{Debug, Display};
fn audit_And_clone<T: Display + Debug + Clone>(item: &T) -> T {
println!("Display view: {item}");
println!("Debug view: {item:?}");
item.clone()
}
fn main() {
let original = String::from("release-v2.1");
let copy = audit_And_clone(&original);
println!("Cloned copy: {copy}");
}
Display view: release-v2.1
Debug view: "release-v2.1"
Cloned copy: release-v2.1
Multiple Bounds Across Multiple Type Parameters
When a signature has more than one generic parameter and each carries multiple trait bounds, you can write them inline or move them into a where clause:
use std::fmt::Display;
use std::hash::Hash;
// Inline syntax:
fn describe_entry_inline<K: Display + Eq + Hash, V: Display + Default>(key: K, value: Option<V>) {
let resolved = value.unwrap_or_default();
println!("{key} => {resolved}");
}
// Equivalent `where` clause syntax:
fn describe_entry_where<K, V>(key: K, value: Option<V>)
where
K: Display + Eq + Hash,
V: Display + Default,
{
let resolved = value.unwrap_or_default();
println!("{key} => {resolved}");
}
fn main() {
describe_entry_inline("timeout_sec", Some(30_u32));
describe_entry_where("retries", None::<u32>);
}
timeout_sec => 30
retries => 0
Combining Trait Bounds with Lifetime Bounds
The + syntax also combines trait bounds with lifetime bounds such as 'static or 'a. For example, T: Send + Sync + 'static requires T to be safe to transfer and share across threads and free of any non-'static borrowed references:
use std::fmt::Debug;
use std::thread;
fn spawn_printer<T>(payload: T) -> thread::JoinHandle<()>
where
T: Debug + Send + 'static,
{
thread::spawn(move || {
println!("Worker thread received: {payload:?}");
})
}
fn main() {
let handle = spawn_printer(vec![10, 20, 30]);
handle.join().unwrap();
}
Worker thread received: [10, 20, 30]
Partial Satisfaction Fails at Compile Time
A concrete type passed to T: TraitA + TraitB must implement all listed traits. If a type implements TraitA (Debug) but not TraitB (Clone), the compiler reports specifically which missing trait caused the failure:
// ❌ does not compile
use std::fmt::Debug;
#[derive(Debug)]
struct NonCloneToken(u64);
fn duplicate_debug<T: Debug + Clone>(val: &T) -> T {
println!("{val:?}");
val.clone()
}
fn main() {
let token = NonCloneToken(99);
let _copy = duplicate_debug(&token);
}
error[E0277]: the trait bound `NonCloneToken: Clone` is not satisfied
--> src/main.rs:14:33
|
14 | let _copy = duplicate_debug(&token);
| --------------- ^^^^^^ the trait `Clone` is not implemented for `NonCloneToken`
| |
| required by a bound introduced by this call
|
note: required by a bound in `duplicate_debug`
--> src/main.rs:7:31
|
7 | fn duplicate_debug<T: Debug + Clone>(val: &T) -> T {
| ^^^^^ required by this bound in `duplicate_debug`