Traits and generics without tears
Shared behavior in Rust: traits, trait bounds, and when to use generics.
Table of Contents
Rust has no inheritance, so shared behavior comes from traits. Think of a trait as a contract: any type that signs it must provide these methods.
Defining and implementing
trait Summary {
fn summarize(&self) -> String;
}
struct Release {
product: String,
version: String,
}
impl Summary for Release {
fn summarize(&self) -> String {
format!("{} {}", self.product, self.version)
}
}
Using it generically
Trait bounds say “any T that fulfills the contract”:
fn announce(item: &impl Summary) {
println!("Update! {}", item.summarize());
}
Choosing between them
impl Traitin argument position: quick, readable, usually enough- Explicit
<T: Summary>: needed when you refer toTmore than once - Trait objects (
dyn Summary): one collection holding mixed types, tiny runtime cost
Combined with ownership from part 1, traits and generics cover most of the architecture you’ll express in Rust day to day.