🦀 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

566: Nested Pattern Matching

Difficulty: 2 Level: Beginner Match deeply nested structures in one expression — no intermediate bindings, no nested ifs.

The Problem This Solves

Imagine a card game. You want to check: is this `Hand::One`, and does it contain an `Ace`, and is the suit specifically `Spades`? In a language without nested patterns, you write three levels of if/instanceof checks. You pull `.r` then check its type, then pull `.s`, and the logic dissolves into scaffolding. With nested patterns, you write the shape of what you're looking for and Rust either matches it or doesn't. The logic reads like a description: "a hand of one card, where the rank is Ace and the suit is Spades." No intermediaries. The second problem is combinatorial matching. You want to handle `(Some(x), Some(y))` differently from `(Some(x), None)`, `(None, Some(y))`, and `(None, None)`. Nested if-let chains get unwieldy fast. A tuple pattern in a `match` handles all four cases in four arms, each self-describing.

The Intuition

Nested patterns work because patterns can be composed: any place you'd write a value, you can write a pattern instead. `Hand::One(Card { r: Rank::A, s: Suit::S })` is just a pattern nested inside a pattern nested inside a pattern. Rust evaluates them inside-out and either all match or none do. Python's `match` (3.10+) has this too, though it uses class patterns. OCaml has it natively and it's one of the most productive features of the language. The concept is the same: instead of querying an object layer by layer, you describe the shape you want and let the runtime/compiler check it in one shot. The key insight: Rust can match on tuples too, so `match (opt1, opt2) { (Some(x), Some(y)) => ... }` gives you a 2D dispatch table in a few clean arms.

How It Works in Rust

enum Rank { N(u8), J, Q, K, A }
enum Suit { C, D, H, S }
struct Card { r: Rank, s: Suit }
enum Hand { Empty, One(Card), Two(Card, Card) }

fn describe(h: &Hand) -> &'static str {
 match h {
     // Nested three levels deep in one arm
     Hand::One(Card { r: Rank::A, s: Suit::S }) => "ace of spades!",

     // Match the outer shape, ignore inner details
     Hand::One(Card { r: Rank::A, .. })          => "an ace",

     // Pattern guard on destructured inner fields
     Hand::Two(Card { r: r1, .. }, Card { r: r2, .. }) if r1 == r2 => "a pair",

     Hand::Two(_, _) => "two cards",
     Hand::Empty     => "nothing",
 }
}

// Tuple patterns: dispatch on two values simultaneously
match (left, right) {
 (Some(x), Some(y)) => format!("both: {} {}", x, y),
 (Some(x), None)    => format!("only left: {}", x),
 (None, Some(y))    => format!("only right: {}", y),
 (None, None)       => "neither".into(),
}

// Nested array/slice patterns
if let [[a, _], [_, d]] = [[1, 2], [3, 4]] {
 println!("Diagonal: {} {}", a, d);  // a=1, d=4
}

What This Unlocks

Key Differences

ConceptOCamlRust
Nested record patterns`{ r = A; s = S }``Card { r: Rank::A, s: Suit::S }`
Tuple match`match (a, b) with (Some x, Some y) ->``match (a, b) { (Some(x), Some(y)) => }`
Pattern guard`when r1 = r2``if r1 == r2`
Skip fields`{ r = A; _ }``Card { r: Rank::A, .. }`
Array pattern`[a; _; b]` (list)`[a, _, b]` (array/slice)
#[derive(Debug,Clone,PartialEq)]
enum Suit { C, D, H, S }
#[derive(Debug,Clone,PartialEq)]
enum Rank { N(u8), J, Q, K, A }
#[derive(Debug,Clone)]
struct Card { r: Rank, s: Suit }
#[derive(Debug)]
enum Hand { Empty, One(Card), Two(Card,Card) }

fn rank_val(r: &Rank) -> u32 {
    match r { Rank::N(n)=>*n as u32, Rank::J|Rank::Q|Rank::K=>10, Rank::A=>11 }
}

fn hand_pts(h: &Hand) -> u32 {
    match h {
        Hand::Empty       => 0,
        Hand::One(c)      => rank_val(&c.r),
        Hand::Two(a,b)    => rank_val(&a.r) + rank_val(&b.r),
    }
}

fn describe(h: &Hand) -> &'static str {
    match h {
        Hand::One(Card{r:Rank::A, s:Suit::S}) => "ace of spades!",
        Hand::One(Card{r:Rank::A, ..})        => "an ace",
        Hand::Two(Card{r:r1,..},Card{r:r2,..}) if r1==r2 => "a pair",
        Hand::Two(_,_)                         => "two cards",
        Hand::Empty                            => "nothing",
    }
}

fn main() {
    let h1 = Hand::One(Card{r:Rank::A, s:Suit::S});
    let h2 = Hand::Two(Card{r:Rank::K,s:Suit::H}, Card{r:Rank::K,s:Suit::C});
    println!("{} ({} pts)", describe(&h1), hand_pts(&h1));
    println!("{} ({} pts)", describe(&h2), hand_pts(&h2));

    // Nested array patterns
    if let [[a,_],[_,d]] = [[1,2],[3,4]] { println!("Diagonal: {} {}", a, d); }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test] fn ace_spades() {
        assert_eq!(describe(&Hand::One(Card{r:Rank::A,s:Suit::S})), "ace of spades!");
    }
    #[test] fn pair_pts() {
        let h = Hand::Two(Card{r:Rank::N(7),s:Suit::H}, Card{r:Rank::N(3),s:Suit::C});
        assert_eq!(hand_pts(&h), 10);
    }
}
(* Nested pattern matching *)
type suit = C | D | H | S
type rank = N of int | J | Q | K | A
type card = { r: rank; s: suit }
type hand = Empty | One of card | Two of card * card

let hand_pts = function
  | Empty -> 0
  | One c -> (match c.r with N n->n | J|Q|K->10 | A->11)
  | Two(a,b) ->
    let rv = function N n->n | J|Q|K->10 | A->11 in
    rv a.r + rv b.r

let describe = function
  | One { r=A; s=S } -> "ace of spades!"
  | One { r=A; _ }   -> "an ace"
  | Two({ r=r1;_},{r=r2;_}) when r1=r2 -> "a pair"
  | Two _             -> "two cards"
  | Empty             -> "nothing"

let () =
  let h1 = One {r=A;s=S} in
  let h2 = Two({r=K;s=H},{r=K;s=C}) in
  Printf.printf "%s (%d pts)\n" (describe h1) (hand_pts h1);
  Printf.printf "%s (%d pts)\n" (describe h2) (hand_pts h2)