Rust Structs & Enums

Rust has no classes. Instead, it uses structs for data and enums for variants. Combined with impl blocks, they give you everything classes provide — plus more.

Structs

Rust
struct Book {
    title: String,
    author: String,
    pages: u32,
}

impl Book {
    // Constructor
    fn new(title: &str, author: &str, pages: u32) -> Self {
        Self { title: title.into(), author: author.into(), pages }
    }

    // Method
    fn summary(&self) -> String {
        format!("{} by {} ({} pages)", self.title, self.author, self.pages)
    }
}

let book = Book::new("Palpasa Cafe", "Narayan Wagle", 312);
println!("{}", book.summary());

Tuple Structs

Rust
struct Color(u8, u8, u8);
struct Point(f64, f64, f64);

let red = Color(255, 0, 0);
let origin = Point(0.0, 0.0, 0.0);

Enums with Data

Enums in Rust can hold data — each variant can be different:

Rust
enum Shape {
    Circle(f64),
    Rectangle { width: f64, height: f64 },
    Triangle(f64, f64, f64),
}

fn area(shape: &Shape) -> f64 {
    match shape {
        Shape::Circle(r) => std::f64::consts::PI * r * r,
        Shape::Rectangle { width, height } => width * height,
        Shape::Triangle(a, b, c) => {
            let s = (a + b + c) / 2.0;
            (s * (s - a) * (s - b) * (s - c)).sqrt()
        }
    }
}

Pattern Matching

match is Rust's most powerful control flow — it must cover all possibilities:

Rust
enum Coin { Penny, Nickel, Dime, Quarter }

fn value_in_cents(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

Option<T>

Rust has no null. Use Option<T> for nullable values:

Rust
fn find_user(id: u32) -> Option<String> {
    if id == 1 {
        Some("Sita".into())
    } else {
        None
    }
}

match find_user(1) {
    Some(name) => println!("Found: {name}"),
    None => println!("Not found"),
}

// Or use combinators
let name = find_user(1).unwrap_or("Unknown".into());

Tips

  • Use impl blocks to add methods to structs and enums.
  • Use match instead of if/else chains — it is exhaustive and the compiler ensures you cover all cases.
  • Option<T> replaces null — no more null pointer exceptions.
  • Use #[derive(Debug)] to print structs for debugging.

Next: error handling — no exceptions, just Results.