Advanced Traits
Associated Types vs Generics
Associated types enforce single implementation per type:
trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; } impl Iterator for Counter { type Item = u32; // Only one Item type allowed // ... }
Generics allow multiple implementations:
trait Iterator<T> { fn next(&mut self) -> Option<T>; } // Could implement Iterator<u32>, Iterator<String>, etc.
Default Generic Type Parameters
trait Add<Rhs = Self> { type Output; fn add(self, rhs: Rhs) -> Self::Output; } // Default: Point + Point impl Add for Point { type Output = Point; fn add(self, other: Point) -> Point { /* ... */ } } // Custom: Point + Meters impl Add<Meters> for Point { type Output = Point; fn add(self, other: Meters) -> Point { /* ... */ } }
Use cases: Extending traits without breaking existing code, mixed-type operations.
Method Disambiguation
Multiple traits, same method names:
trait Pilot { fn fly(&self); } trait Wizard { fn fly(&self); } struct Human; impl Pilot for Human { fn fly(&self) { println!("Flying a plane"); } } impl Wizard for Human { fn fly(&self) { println!("Flying with magic"); } } let person = Human; Pilot::fly(&person); // Explicit trait Wizard::fly(&person); // Explicit trait
Associated functions (no self
):
println!("{}", <Dog as Animal>::baby_name()); // Fully qualified syntax
Supertraits
Require implementing one trait before another:
trait OutlinePrint: fmt::Display { fn outline_print(&self) { println!("* {} *", self); // Can use Display::fmt } } // Must implement Display before OutlinePrint impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) } }
Newtype Pattern
Circumvent orphan rule (implement external traits on external types):
struct Wrapper(Vec<String>); impl fmt::Display for Wrapper { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}]", self.0.join(", ")) } } let w = Wrapper(vec![String::from("hello"), String::from("world")]); println!("w = {}", w);
Additional benefits:
- Type safety:
UserId(u32)
vsProductId(u32)
- Zero runtime cost
- Controlled API surface
Access wrapped value with Deref
:
impl Deref for Wrapper { type Target = Vec<String>; fn deref(&self) -> &Self::Target { &self.0 } }