shapes.rs in Rust
Trait objects and generics together: a shape registry that measures and sorts.
use std::f64::consts::PI;
use std::fmt;
trait Shape {
fn name(&self) -> &'static str;
fn area(&self) -> f64;
fn describe(&self) -> String {
format!("{} of area {:.2}", self.name(), self.area())
}
}
struct Circle {
radius: f64,
}
struct Rect {
width: f64,
height: f64,
}
struct Triangle {
base: f64,
height: f64,
}
impl Shape for Circle {
fn name(&self) -> &'static str {
"circle"
}
fn area(&self) -> f64 {
PI * self.radius * self.radius
}
}
impl Shape for Rect {
fn name(&self) -> &'static str {
"rectangle"
}
fn area(&self) -> f64 {
self.width * self.height
}
fn describe(&self) -> String {
format!("{:.0}x{:.0} rectangle", self.width, self.height)
}
}
impl Shape for Triangle {
fn name(&self) -> &'static str {
"triangle"
}
fn area(&self) -> f64 {
self.base * self.height / 2.0
}
}
impl fmt::Display for Circle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "circle r={}", self.radius)
}
}
fn total_area<T: Shape>(shapes: &[T]) -> f64 {
shapes.iter().map(|s| s.area()).sum()
}
fn main() {
let mut shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 1.5 }),
Box::new(Rect { width: 4.0, height: 2.0 }),
Box::new(Triangle { base: 3.0, height: 4.0 }),
];
shapes.sort_by(|a, b| a.area().partial_cmp(&b.area()).unwrap());
for s in &shapes {
println!("{}", s.describe());
}
let boxes = [
Rect { width: 1.0, height: 1.0 },
Rect { width: 2.0, height: 3.0 },
];
println!("rect total {:.1}", total_area(&boxes));
println!("{}", Circle { radius: 2.0 });
}
How it works
- One trait with a default method covers every shape.
- The shapes live in a
Vec<Box<dyn Shape>>, sorted by area. - A generic helper totals anything that implements the trait.
Keywords and builtins used here
BoxCircleRectResultShapeStringTriangleVecareadescribedynf64fmtfnforimplinletmainmutnameselfstaticstrstructtotal_areatraituse
The run, in numbers
- Lines
- 86
- Characters to type
- 1489
- Tokens
- 496
- Three-star pace
- 110 tpm
At the three-star pace of 110 tokens a minute, this run takes about 271 seconds.
Step 1 of 1 in Encore, step 19 of 19 in Traits & generics.