Traits as Function Parameters
Rust provides three ways to accept values implementing a trait as function parameters: argument-position impl Trait (item: &impl Trait), explicit generic type parameters (<T: Trait>(item: &T)), and trait object references (item: &dyn Trait).
Argument-Position impl Trait Syntax
Writing impl Trait in a parameter type (fn notify(item: &impl Summary)) introduces an anonymous generic type parameter constrained by Summary:
trait Summary {
fn summarize(&self) -> String;
}
struct Alert {
severity: &'static str,
message: &'static str,
}
impl Summary for Alert {
fn summarize(&self) -> String {
format!("[{}] {}", self.severity, self.message)
}
}
fn notify(item: &impl Summary) {
println!("Notification: {}", item.summarize());
}
fn main() {
let alert = Alert {
severity: "WARN",
message: "Disk usage above 85%",
};
notify(&alert);
}
Notification: [WARN] Disk usage above 85%
Critical Difference Between Multiple impl Trait Parameters and <T: Trait>
When a function takes two parameters using impl Trait, each impl Trait introduces a separate, independent anonymous type parameter—allowing the caller to pass two different concrete types:
fn compare_any(a: &impl Summary, b: &impl Summary)
Desugars to:
fn compare_any<T: Summary, U: Summary>(a: &T, b: &U) // a and b CAN have different types
fn compare_same<T: Summary>(a: &T, b: &T) // a and b MUST have the exact same type T
use std::fmt::Display;
// Accepts ANY two types that each implement Display:
fn print_pair_independent(left: &impl Display, right: &impl Display) {
println!("Independent: ({left}, {right})");
}
// Forces BOTH arguments to have the exact same concrete type T:
fn print_pair_identical<T: Display>(left: &T, right: &T) {
println!("Identical: ({left}, {right})");
}
fn main() {
// Mixed types (&i32 and &&str) work with two `impl Display` parameters:
print_pair_independent(&42, &"forty-two");
// Identical types (&i32 and &i32) are required for `<T: Display>(left: &T, right: &T)`:
print_pair_identical(&10, &20);
}
Independent: (42, forty-two)
Identical: (10, 20)
Disallowing Explicit Turbofish Arguments with impl Trait (E0632)
When a function uses impl Trait in parameter position, callers cannot supply explicit type arguments for that parameter via turbofish (func::<ConcreteType>(...)). If callers need turbofish support, declare a named type parameter <T: Trait> instead:
// ❌ does not compile
use std::fmt::Display;
fn show(value: impl Display) {
println!("{value}");
}
fn main() {
show::<i32>(10);
}
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> src/main.rs:8:12
|
8 | show::<i32>(10);
| ^^^ explicit generic argument not permitted
Comparing the Three Parameter Styles
| Parameter Syntax | Dispatch | Two Params Same Type? | Turbofish Allowed? |
|---|---|---|---|
fn f(a: &impl Trait, b: &impl Trait) |
Static (monomorphized) | No (a and b can differ) |
No (E0632) |
fn f<T: Trait>(a: &T, b: &T) |
Static (monomorphized) | Yes (both must be T) |
Yes (f::<MyType>(...)) |
fn f(a: &dyn Trait, b: &dyn Trait) |
Dynamic (vtable) | No (a and b can differ) |
N/A (not generic) |