Enums and Pattern Matching

Destructuring Structs, Tuples, and Enums

Destructuring unpacks a composite value—a tuple, struct, tuple struct, or enum variant—into its constituent parts using a pattern that mirrors the syntax used to construct the value.

Side-by-Side Destructuring Syntax Reference

Type Category Construction Syntax Destructuring Pattern Syntax
Tuple (10, "ok", true) (code, msg, active) or (code, ..)
Named-field struct Point { x: 1, y: 2 } Point { x, y } (shorthand) or Point { x: a, y: b } (renamed) or Point { x, .. }
Tuple struct Color(255, 0, 128) Color(r, g, b) or Color(r, ..)
Unit enum variant State::Idle State::Idle
Tuple enum variant State::Retry(3, 500) State::Retry(attempts, delay_ms)
Struct enum variant State::Active { pid: 9, port: 80 } State::Active { pid, port } or State::Active { pid, .. }

Destructuring Named-Field Structs (Field Shorthand and Renaming)

When destructuring a named-field struct:

  • Field shorthand (Point { x, y }): Creates local variables x and y with the same names as the fields.
  • Explicit renaming (Point { x: px, y: py }): Binds field x to local variable px and field y to py.
  • Literal field matching (Point { x: 0, y }): Matches only when field x == 0 and binds y.
struct Server {
    host: &'static str,
    port: u16,
    tls: bool,
}

fn main() {
    let srv = Server {
        host: "api.example.com",
        port: 443,
        tls: true,
    };

    // 1. Shorthand for `host`, rename `port` to `server_port`, ignore `tls` with `..`:
    let Server {
        host,
        port: server_port,
        ..
    } = srv;
    println!("Connecting to {host} on port {server_port}");

    // 2. Match literal field values inside a struct pattern:
    match srv {
        Server { port: 443, tls: true, host } => println!("Standard HTTPS on {host}"),
        Server { tls: true, host, port } => println!("Custom HTTPS on {host}:{port}"),
        Server { host, port, .. } => println!("Plain HTTP on {host}:{port}"),
    }
}
Connecting to api.example.com on port 443
Standard HTTPS on api.example.com

Destructuring Tuples in Function Parameters and for Loops

Because tuples and single-variant structs have irrefutable patterns, you can destructure them directly in let statements, for loops, and function/closure parameter lists:

struct Pair(i32, i32);

// Destructure a tuple `(i32, i32)` and a tuple struct `Pair` directly in the signature:
fn dot_product((x1, y1): (i32, i32), Pair(x2, y2): Pair) -> i32 {
    (x1 * x2) + (y1 * y2)
}

fn main() {
    let result = dot_product((3, 4), Pair(10, 20));
    println!("Dot product = {result}");

    let items = ["alpha", "beta", "gamma"];
    // Destructure the `(usize, &&str)` tuple yielded by `.enumerate()`:
    for (index, &word) in items.iter().enumerate() {
        println!("[{index}] {word}");
    }
}
Dot product = 110
[0] alpha
[1] beta
[2] gamma

Destructuring All Three Enum Variant Kinds

An enum can mix unit, tuple, and struct variants in the same type, and each variant is destructured using its corresponding construction syntax:

enum Command {
    Ping,
    Echo(String),
    Move { dx: i32, dy: i32 },
}

fn execute(cmd: Command) {
    match cmd {
        Command::Ping => println!("PONG"),
        Command::Echo(text) => println!("ECHO: {text}"),
        Command::Move { dx, dy } => println!("MOVE by ({dx}, {dy})"),
    }
}

fn main() {
    execute(Command::Ping);
    execute(Command::Echo(String::from("hello")));
    execute(Command::Move { dx: -5, dy: 12 });
}
PONG
ECHO: hello
MOVE by (-5, 12)