Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rust - Structs, Enums & Pattern Matching

Structs

#![allow(unused)]
fn main() {
struct User {
    username: String,
    email: String,
    age: u32,
    active: bool,
}

let user = User {
    username: String::from("gbraad"),
    email: String::from("me@gbraad.nl"),
    age: 30,
    active: true,
};

println!("{}", user.username);

// Update syntax - copy remaining fields from another instance
let user2 = User {
    email: String::from("other@example.com"),
    ..user   // moves remaining fields from user
};
}

Tuple structs

#![allow(unused)]
fn main() {
struct Color(u8, u8, u8);
struct Point(f64, f64);

let black = Color(0, 0, 0);
let origin = Point(0.0, 0.0);
println!("{}", black.0);
}

Methods

#![allow(unused)]
fn main() {
#[derive(Debug)]
struct Rectangle {
    width: f64,
    height: f64,
}

impl Rectangle {
    // Associated function (constructor, no self)
    fn new(width: f64, height: f64) -> Self {
        Rectangle { width, height }
    }

    // Method (takes &self)
    fn area(&self) -> f64 {
        self.width * self.height
    }

    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

let rect = Rectangle::new(10.0, 5.0);
println!("Area: {}", rect.area());
println!("{rect:#?}");   // needs #[derive(Debug)]
}

Enums

#![allow(unused)]
fn main() {
enum Direction {
    North,
    South,
    East,
    West,
}

let dir = Direction::North;
}

Enum variants can carry data:

#![allow(unused)]
fn main() {
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    Color(u8, u8, u8),
}

impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("quit"),
            Message::Move { x, y } => println!("move to {x},{y}"),
            Message::Write(text) => println!("write: {text}"),
            Message::Color(r, g, b) => println!("color: {r},{g},{b}"),
        }
    }
}
}

Option

Option<T> replaces null - a value is either Some(T) or None:

#![allow(unused)]
fn main() {
let some_number: Option<i32> = Some(5);
let no_number: Option<i32> = None;

// Must handle both cases before using the value
let value = some_number.unwrap_or(0);
let doubled = some_number.map(|n| n * 2);
}

Pattern matching

match

#![allow(unused)]
fn main() {
let coin = Coin::Quarter;
let value = match coin {
    Coin::Penny   => 1,
    Coin::Nickel  => 5,
    Coin::Dime    => 10,
    Coin::Quarter => 25,
};

// Catch-all
match number {
    1 => println!("one"),
    2 | 3 => println!("two or three"),
    4..=9 => println!("four to nine"),
    other => println!("got {other}"),  // binds the value
    // _ => ()                         // discard catch-all
}

// Destructuring in match
match msg {
    Message::Move { x, y } => println!("{x},{y}"),
    Message::Write(text)   => println!("{text}"),
    _ => (),
}
}

if let - single-arm match shorthand

#![allow(unused)]
fn main() {
let config_max = Some(3u8);
if let Some(max) = config_max {
    println!("max is {max}");
}

if let Some(n) = some_value {
    println!("{n}");
} else {
    println!("nothing");
}
}

while let

#![allow(unused)]
fn main() {
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
    println!("{top}");
}
}

Collections

Vec

#![allow(unused)]
fn main() {
let mut v: Vec<i32> = Vec::new();
let v2 = vec![1, 2, 3];     // macro shorthand

v.push(4);
v.push(5);

let third = &v[2];           // panics if out of bounds
let third = v.get(2);        // returns Option<&i32>

for n in &v {
    println!("{n}");
}
for n in &mut v {
    *n += 10;                // dereference to modify
}

v.pop();                     // removes and returns last element
v.len();
v.is_empty();
}

HashMap

#![allow(unused)]
fn main() {
use std::collections::HashMap;

let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("Alice"), 100);
scores.insert(String::from("Bob"), 85);

// Access
let alice = scores.get("Alice");     // Option<&i32>
let alice = scores["Alice"];         // panics if missing

// Insert only if key absent
scores.entry(String::from("Charlie")).or_insert(70);

// Iterate
for (name, score) in &scores {
    println!("{name}: {score}");
}
}