Traits

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)