पाठ 13 / 25
Traits and Generics
Shared behaviour, static or dynamic dispatch.
impl Trait for Type
A trait declares methods a type can implement, optionally with default implementations; impl Shape for Rect provides them. Generics with trait bounds (fn largest<T: PartialOrd + Copy>) work for any type meeting the bounds and are compiled to specialised code (static dispatch, no runtime cost). Trait objects (Box<dyn Shape>) allow mixing different types in one collection at the cost of dynamic dispatch. Implementing standard traits such as Display integrates your types with the language (formatting with {}).
A Shape trait, Display, generics and trait objects, run
I ran this with Rust 1.99.0 (cargo run, edition 2024, standard library only). A vector of boxed trait objects holds a Rect and a Circle and sums their areas; Circle uses the default name method; Display controls {} printing; the generic largest works for integers and floats.
use std::fmt;
trait Shape {
fn area(&self) -> f64;
fn name(&self) -> String { "shape".to_string() } // default method
}
struct Rect { w: f64, h: f64 }
struct Circle { r: f64 }
impl Shape for Rect {
fn area(&self) -> f64 { self.w * self.h }
fn name(&self) -> String { "rect".to_string() }
}
impl Shape for Circle {
fn area(&self) -> f64 { std::f64::consts::PI * self.r * self.r }
}
impl fmt::Display for Circle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Circle(r={})", self.r) }
}
fn largest<T: PartialOrd + Copy>(items: &[T]) -> T { // generic with trait bounds
let mut m = items[0];
for &x in items { if x > m { m = x; } }
m
}
fn total_area(shapes: &[Box<dyn Shape>]) -> f64 { // dynamic dispatch
shapes.iter().map(|s| s.area()).sum()
}
fn main() {
let shapes: Vec<Box<dyn Shape>> = vec![Box::new(Rect { w: 3.0, h: 4.0 }), Box::new(Circle { r: 1.0 })];
println!("total area {:.2}", total_area(&shapes));
println!("{} {}", shapes[0].name(), shapes[1].name());
println!("{}", Circle { r: 2.0 });
println!("{} {:.1}", largest(&[3, 9, 4]), largest(&[1.5, 0.5]));
}
Output:
total area 15.14 rect shape Circle(r=2) 9 1.5
Prefer generics, use dyn when mixing types
Generics are zero-cost; reach for dyn Trait when you need a heterogeneous collection or smaller binaries.
त्वरित जाँच: What does Box<dyn Shape> enable?
- Faster static dispatch
- Storing different types that implement Shape in one collection
- Avoiding the trait entirely
- Garbage collection
Answer
Storing different types that implement Shape in one collection — Trait objects use dynamic dispatch.