typestar

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

  1. One trait with a default method covers every shape.
  2. The shapes live in a Vec<Box<dyn Shape>>, sorted by area.
  3. A generic helper totals anything that implements the trait.

Keywords and builtins used here

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.

Type this snippet

Step 1 of 1 in Encore, step 19 of 19 in Traits & generics.

← Previous