๐Ÿฆ€ 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

570: Slice Patterns: [first, rest @ ..]

Difficulty: 2 Level: Beginner Match arrays and slices by shape โ€” branch on length and extract elements in one expression.

The Problem This Solves

Processing a slice differently based on its length means a nest of index checks: `if s.is_empty()`, then `else if s.len() == 1`, then `else if s.len() == 2`, then access `s[0]`, `s[1]`, hope you got the bounds right. It's boilerplate scaffolding around a conceptually simple idea. The deeper issue is structural recursion. Functional algorithms like sum and product are naturally recursive on lists: "if empty return base case, otherwise take the head and recurse on the tail." In most imperative languages you'd convert this to a loop, losing the clean recursive structure. Slice patterns restore it: `[x, rest @ ..]` gives you the head and tail directly, matching the mathematical definition. The `..` wildcard is particularly useful for "first and last" patterns. You want the first element for one thing and the last for another, and you don't care how many are in between. Previously you'd call `.first()` and `.last()` separately. With slice patterns: `[first, .., last]`.

The Intuition

Slice patterns describe the shape of a slice. `[]` means empty. `[x]` means exactly one element, bound to `x`. `[a, b]` means exactly two. `[a, b, ..]` means "at least two, ignore the rest." `[first, .., last]` means "at least two, I want the first and last." This is OCaml's list pattern `x :: xs` generalized to contiguous memory. OCaml matches on cons cells (`::` is the list constructor), so it's `[]` for empty and `head :: tail` for non-empty. Rust matches on actual memory slices, so `[x, rest @ ..]` is the equivalent. The `rest @ ..` part uses `@` to bind the remaining elements as a sub-slice. The key insight: this works on `&[T]`, `[T; N]` (fixed-size arrays), and anything that coerces to a slice. One syntax, any contiguous collection.

How It Works in Rust

// Recursive sum via slice pattern
fn sum(s: &[i32]) -> i32 {
 match s {
     []             => 0,              // base case: empty
     [x, rest @ ..] => x + sum(rest),  // head + recurse on tail
 }
}

// Describe by shape โ€” matches on exact lengths and first/last
fn describe(s: &[i32]) -> String {
 match s {
     []              => "empty".into(),
     [x]             => format!("one: {}", x),
     [a, b]          => format!("pair: ({},{})", a, b),
     [first, .., last] => format!("many: {}..{}", first, last),
 }
}

// Extract only what you need
fn first_two(s: &[i32]) -> Option<(i32, i32)> {
 match s {
     [a, b, ..] => Some((*a, *b)),  // at least 2 elements
     _          => None,
 }
}

// Mutation via ref mut in slice pattern
fn double_first(v: &mut [i32]) {
 if let [ref mut first, ..] = v {
     *first *= 2;
 }
}

What This Unlocks

Key Differences

ConceptOCamlRust
Head/tail`x :: xs` (list cons)`[x, rest @ ..]` (slice pattern)
Empty`[]``[]`
Fixed two elements`[a; b]``[a, b]`
First and lastNo direct syntax`[first, .., last]`
Data structureLinked list (`list`)Contiguous slice (`&[T]`)
Sub-slice bindingN/A (list tail is natural)`rest @ ..` binds remaining elements
fn sum(s: &[i32]) -> i32 {
    match s {
        []            => 0,
        [x, rest @ ..] => x + sum(rest),
    }
}

fn product(s: &[i32]) -> i32 {
    match s {
        []            => 1,
        [x, rest @ ..] => x * product(rest),
    }
}

fn first_two(s: &[i32]) -> Option<(i32,i32)> {
    match s { [a,b,..] => Some((*a,*b)), _ => None }
}

fn last(s: &[i32]) -> Option<i32> {
    match s { [] => None, [x] => Some(*x), [_,rest@..] => last(rest) }
}

fn describe(s: &[i32]) -> String {
    match s {
        []              => "empty".into(),
        [x]             => format!("one: {}", x),
        [a,b]           => format!("pair: ({},{})", a, b),
        [first,..,last] => format!("many: {}..{}", first, last),
    }
}

fn main() {
    let xs = [1,2,3,4,5];
    println!("sum={} product={}", sum(&xs), product(&xs));
    println!("first_two: {:?}", first_two(&xs));
    println!("last: {:?}", last(&xs));
    for s in [&[][..],&[1][..],&[1,2][..],&[1,2,3,4][..]] {
        println!("describe {:?}: {}", s, describe(s));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test] fn test_sum()     { assert_eq!(sum(&[1,2,3,4,5]), 15); }
    #[test] fn test_last()    { assert_eq!(last(&[1,2,3]), Some(3)); }
    #[test] fn test_describe(){ assert_eq!(describe(&[]), "empty"); }
}
(* List patterns in OCaml *)
let rec sum = function
  | []      -> 0
  | x :: xs -> x + sum xs

let rec product = function
  | []      -> 1
  | x :: xs -> x * product xs

let first_two = function
  | a :: b :: _ -> Some (a, b)
  | _           -> None

let describe = function
  | []          -> "empty"
  | [x]         -> Printf.sprintf "one: %d" x
  | [a;b]       -> Printf.sprintf "pair: (%d,%d)" a b
  | h :: _      -> Printf.sprintf "many, first: %d" h

let () =
  let xs = [1;2;3;4;5] in
  Printf.printf "sum=%d product=%d\n" (sum xs) (product xs);
  (match first_two xs with Some(a,b)->Printf.printf "(%d,%d)\n" a b | None->());
  Printf.printf "%s\n" (describe xs)