Destructuring
Destructuring unpacks structs, tuples, enums, and slices into bindings with patterns in let, match, and function parameters.
Recipe
struct Point { x: i32, y: i32 }
fn main() {
let p = Point { x: 1, y: 2 };
let Point { x, y } = p;
println!("{x} {y}");
}When to reach for this: Extracting fields cleanly, matching nested data, and ignoring parts with ...
Working Example
enum Shape {
Circle { radius: f64 },
Rect { w: f64, h: f64 },
}
fn area(s: &Shape) -> f64 {
match s {
Shape::Circle { radius } => std::f64::consts::PI * radius * radius,
Shape::Rect { w, h } => w * h,
}
}
fn main() {
let shapes = [Shape::Circle { radius: 2.0 }, Shape::Rect { w: 3.0, h: 4.0 }];
let total: f64 = shapes.iter().map(area).sum();
println!("{total}");
}What this demonstrates:
- Struct variant destructuring in
match - References
&Shapeavoid moving - Tuple/array destructuring available similarly
@bindings:n @ 1..=10captures whole value and subpattern
Deep Dive
Ignoring Fields
let Point { x, .. } = p; // ignore y and rest
let (_, second, ..) = tuple;Nested Patterns
match nested {
Outer::Inner(Point { x: 0, .. }) => {}
_ => {}
}ref / ref mut in Patterns
Bind by reference inside match to avoid moving fields.
Gotchas
- Move on destructuring -
let s = structmoves fields. Fix:match &valorrefpatterns. - Partial move of struct - Some fields moved, others not usable as whole. Fix: Destructure all needed fields or borrow.
- Confusing
..in struct vs match - Update syntax..otherdiffers from pattern rest... Fix: Context determines meaning. - Non-exhaustive struct patterns - Must list all fields unless
... Fix: Add..for ignore rest. - Binding mode changes (edition) - May affect implicit move/copy. Fix: Read Rust 2024 pattern binding docs.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
Field access p.x | One or two fields | Many fields or nested match |
| Accessor methods | Encapsulation | Simple data structs |
if let partial | Single variant | Many shapes |
| Records via macro | Boilerplate reduction | Standard derive enough |
FAQs
Destructure in function args?
`fn f(Point { x, y }: Point)` moves struct into fn.Match tuple?
`match pair { (0, y) => ..., _ => ... }`.Slice patterns?
`[first, rest @ ..]` with slice patterns (advanced).Guard with destructure?
Combine in match arm: `Shape::Rect { w, h } if w == h`.Enum tuple variant?
`MyEnum::Tuple(a, b)` pattern.Ignore with `_`?
`let (x, _) = pair` ignores second.Mutable destructure?
`let mut Point { x, .. } = p` mutates fields.ref mut?
`let Point { ref mut x, .. }` for partial mutable borrow.Compatibility with serde?
Deserialize builds structs - destructuring is separate concern.Performance?
Zero-cost - compiled away like field access.Related
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.