Defining and Implementing Traits
Traits define shared behavior. They are Rust's answer to interfaces, type classes, and abstract classes - but more powerful and more explicit.
// Define a trait
trait Shape {
fn area(&self) -> f64;
fn perimeter(&self) -> f64;
fn name(&self) -> &str;
// Default method - can be overridden
fn describe(&self) -> String {
format!("{}: area={:.2}, perimeter={:.2}", self.name(), self.area(), self.perimeter())
}
}
struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
impl Shape for Circle {
fn area(&self) -> f64 { std::f64::consts::PI * self.radius * self.radius }
fn perimeter(&self) -> f64 { 2.0 * std::f64::consts::PI * self.radius }
fn name(&self) -> &str { "Circle" }
}
impl Shape for Rectangle {
fn area(&self) -> f64 { self.width * self.height }
fn perimeter(&self) -> f64 { 2.0 * (self.width + self.height) }
fn name(&self) -> &str { "Rectangle" }
// Uses default describe()
}
// Accept any type implementing Shape
fn print_shape_info(shape: &impl Shape) {
println!("{}", shape.describe());
}
fn main() {
let c = Circle { radius: 5.0 };
let r = Rectangle { width: 4.0, height: 3.0 };
print_shape_info(&c);
print_shape_info(&r);
}Trait Objects
fn total_area(shapes: &[Box]) -> f64 {
shapes.iter().map(|s| s.area()).sum()
}
fn main() {
let shapes: Vec> = vec![
Box::new(Circle { radius: 3.0 }),
Box::new(Rectangle { width: 4.0, height: 5.0 }),
Box::new(Circle { radius: 1.0 }),
];
for s in &shapes { println!("{}", s.describe()); }
println!("Total area: {:.2}", total_area(&shapes));
} 🎯 Practice
- Create a Drawable trait with a draw(&self) -> String method. Implement for several types.
- Create a Sortable trait with compare(&self, other: &Self) -> std::cmp::Ordering. Implement for a custom struct.
- Write a function that takes Vec<Box<dyn Shape>> and returns the largest shape by area
🎉 Key Takeaways
- Traits define shared behavior via method signatures
- Default implementations provide behavior that can be overridden
- impl Trait in parameters = static dispatch (monomorphized, fast)
- dyn Trait (trait objects) = dynamic dispatch (vtable, flexible)