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 variablesxandywith the same names as the fields. - Explicit renaming (
Point { x: px, y: py }): Binds fieldxto local variablepxand fieldytopy. - Literal field matching (
Point { x: 0, y }): Matches only when fieldx == 0and bindsy.
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)