RsRust · Lesson 4 of 8

Structs & Enums

Rust doesn't have classes, but it has structs + impl blocks, which are better in every way. Fight me.

Rust
#[derive(Debug)]
struct Rectangle {
    width: f64,
    height: f64,
}

impl Rectangle {
    // Associated function (like a static method — no 'self')
    fn new(width: f64, height: f64) -> Self {
        Rectangle { width, height }
    }

    // Method — 'self' is the instance
    fn area(&self) -> f64 {
        self.width * self.height
    }

    fn perimeter(&self) -> f64 {
        2.0 * (self.width + self.height)
    }

    fn is_square(&self) -> bool {
        self.width == self.height
    }

    // Mutable method
    fn scale(&mut self, factor: f64) {
        self.width *= factor;
        self.height *= factor;
    }
}

fn main() {
    let mut rect = Rectangle::new(10.0, 5.0);
    println!("{:?}", rect);            // Rectangle { width: 10.0, height: 5.0 }
    println!("Area: {}", rect.area()); // Area: 50
    rect.scale(2.0);
    println!("Scaled: {:?}", rect);    // Rectangle { width: 20.0, height: 10.0 }
}

Rust's enums are far more powerful than enums in most languages — each variant can hold different types of data. Combined with pattern matching, they make Rust code extremely expressive.

Rust
#[derive(Debug)]
enum Shape {
    Circle(f64),              // radius
    Rectangle(f64, f64),      // width, height
    Triangle { base: f64, height: f64 },  // named fields
}

impl Shape {
    fn area(&self) -> f64 {
        match self {
            Shape::Circle(r) => std::f64::consts::PI * r * r,
            Shape::Rectangle(w, h) => w * h,
            Shape::Triangle { base, height } => 0.5 * base * height,
        }
    }
}

fn main() {
    let shapes = vec![
        Shape::Circle(5.0),
        Shape::Rectangle(4.0, 6.0),
        Shape::Triangle { base: 3.0, height: 8.0 },
    ];

    for shape in &shapes {
        println!("{:?} has area {:.2}", shape, shape.area());
    }
}