๐Ÿฆ€ Functional Rust
๐ŸŽฌ Pattern Matching Exhaustive match, destructuring, guards, let-else โ€” compiler-verified branching.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข match is exhaustive โ€” the compiler ensures every variant is handled

โ€ข Destructuring extracts fields from structs, tuples, and enums in one step

โ€ข Guards (if conditions) add extra logic to match arms

โ€ข if let and let-else provide concise single-pattern matching

โ€ข Nested patterns and @ bindings handle complex data shapes elegantly

563: Struct Destructuring

Difficulty: 2 Level: Beginner Extract struct fields directly into bindings โ€” no `.field` access needed.

The Problem This Solves

Without destructuring, pulling data out of structs is verbose noise. You write `person.name`, `person.age`, `person.age` again, over and over. When a function only cares about two of five fields, you still have to lug the whole struct around and access each field by name at every use site. The real pain shows up in `match` guards: `if person.age < 18` is fine, but when you're pattern-matching on a `Person` wrapped inside an `Option` inside a `Vec`, you end up with deeply nested `.field` chains that bury the actual logic. Struct destructuring lets you name what you want, right where you need it, and ignore the rest with `..`. The signal-to-noise ratio flips: the binding is front-and-center, the struct name is just context.

The Intuition

Think of it as unpacking a labelled box. You write the label you want (`x`, `name`, `age`) and Rust pulls the matching field. You can skip fields with `..`, rename them with `field: local_name`, and combine destructuring with guards in a single `match` arm. Python's dataclasses don't have this at all โ€” you always write `p.x`. JavaScript has object destructuring (`const { x, y } = point`), which is the closest analogy. OCaml's record patterns work the same way. Rust is strict: the field names must match exactly, but you only pay for what you use. The key insight: destructuring works anywhere a pattern is valid โ€” `let`, `match`, function parameters, `if let`, `for` loops.

How It Works in Rust

struct Point { x: f64, y: f64 }
struct Person { name: String, age: u32, email: String }

// Function parameter destructuring โ€” no body boilerplate
fn distance(Point { x, y }: &Point) -> f64 {
 (x * x + y * y).sqrt()  // x and y are directly in scope
}

// Skip fields you don't need with ..
fn greet(Person { name, age, .. }: &Person) -> String {
 format!("Hello {}, age {}", name, age)  // email not mentioned
}

// Destructuring in match + guard
fn classify(person: &Person) -> &'static str {
 match person {
     Person { age, .. } if *age < 18 => "minor",
     Person { age, .. } if *age < 65 => "adult",
     _                               => "senior",
 }
}

// Rename a field: `x: local_name`
let Point { x: px, y: py } = some_point;

// Nested struct destructuring in one let
struct Rect { tl: Point, br: Point }
let Rect { tl: Point { x: x1, y: y1 }, br: Point { x: x2, y: y2 } } = r;

What This Unlocks

Key Differences

ConceptOCamlRust
Syntax`{ x; y; _ }``{ x, y, .. }`
Field rename`{ x = px; _ }``{ x: px, .. }`
ExhaustivenessWarning if field omitted without `_`Compile error; use `..` to skip
In function paramsYes โ€” `let f { x; _ } = ...`Yes โ€” `fn f(Point { x, .. }: &Point)`
Works in `let`YesYes
#[derive(Debug)]
struct Point { x: f64, y: f64 }

#[derive(Debug)]
struct Person { name: String, age: u32, email: String }

fn distance(Point { x, y }: &Point) -> f64 {
    (x * x + y * y).sqrt()
}

fn greet(Person { name, age, .. }: &Person) -> String {
    format!("Hello {}, age {}", name, age)
}

fn classify(person: &Person) -> &'static str {
    match person {
        Person { age, .. } if *age < 18 => "minor",
        Person { age, .. } if *age < 65 => "adult",
        _                               => "senior",
    }
}

fn main() {
    let p = Point { x: 3.0, y: 4.0 };
    println!("dist = {:.1}", distance(&p));
    let alice = Person { name: "Alice".into(), age: 30, email: "a@b.com".into() };
    println!("{}", greet(&alice));
    println!("{}", classify(&alice));

    // Nested destructuring
    struct Rect { tl: Point, br: Point }
    let r = Rect { tl: Point { x: 0.0, y: 4.0 }, br: Point { x: 3.0, y: 0.0 } };
    let Rect { tl: Point { x: x1, y: y1 }, br: Point { x: x2, y: y2 } } = r;
    println!("area = {:.1}", (x2-x1).abs() * (y2-y1).abs());
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test] fn test_dist() { assert_eq!(distance(&Point{x:3.0,y:4.0}), 5.0); }
    #[test] fn test_minor() {
        let p = Person{name:"".into(),age:10,email:"".into()};
        assert_eq!(classify(&p), "minor");
    }
}
(* Record destructuring in OCaml *)
type point = { x: float; y: float }
type person = { name: string; age: int; email: string }

let dist_from_origin { x; y } = sqrt (x*.x +. y*.y)
let greet { name; age; _ } = Printf.sprintf "Hello %s, age %d" name age

let classify_person = function
  | { age; _ } when age < 18 -> "minor"
  | { age; _ } when age < 65 -> "adult"
  | _                        -> "senior"

let () =
  Printf.printf "%.1f\n" (dist_from_origin { x=3.; y=4. });
  let alice = { name="Alice"; age=30; email="a@b.com" } in
  Printf.printf "%s\n" (greet alice);
  Printf.printf "%s\n" (classify_person alice)