title: Destructuring

Destructuring lets you unpack values from compound types directly into variables. It works in let bindings, function parameters, match arms, and for loops.

Tuples

let point = (10, 20);
let (x, y) = point;
 
println!("{x}, {y}");  // 10, 20

Ignore values with _:

let (x, _, z) = (1, 2, 3);  // ignore the middle value

Nested tuples:

let ((a, b), c) = ((1, 2), 3);

Structs

struct Point {
    x: i32,
    y: i32,
}
 
let p = Point { x: 10, y: 20 };
let Point { x, y } = p;
 
println!("{x}, {y}");  // 10, 20

Rename fields while destructuring:

let Point { x: horizontal, y: vertical } = p;

Ignore remaining fields with ..:

struct Config {
    debug: bool,
    verbose: bool,
    timeout: u32,
}
 
let Config { debug, .. } = config;  // only extract debug

Enums

enum Message {
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(u8, u8, u8),
}
 
match msg {
    Message::Move { x, y } => println!("move to {x}, {y}"),
    Message::Write(text) => println!("write: {text}"),
    Message::ChangeColor(r, g, b) => println!("color: {r}, {g}, {b}"),
}

Arrays and slices

Fixed-size arrays:

let [a, b, c] = [1, 2, 3];

Slices with .. to match a variable number of elements:

let numbers = [1, 2, 3, 4, 5];
 
match numbers {
    [first, .., last] => println!("first: {first}, last: {last}"),
}
 
match numbers {
    [first, second, ..] => println!("starts with {first}, {second}"),
}

References

Prefix with & to destructure a reference:

let reference = &42;
let &value = reference;  // value is i32, not &i32

More commonly, use ref inside a pattern to bind by reference rather than by value:

let name = String::from("Alice");
 
match name {
    ref s => println!("got a reference to: {s}"),  // name is not moved
}

In practice you’ll rarely need ref explicitly — borrowing with & in match is more common:

match &name {
    s => println!("{s}"),  // s is &String
}

In function parameters

Destructure directly in the parameter list:

fn print_point(&(x, y): &(i32, i32)) {
    println!("{x}, {y}");
}
 
fn print_user(&User { ref name, age }: &User) {
    println!("{name} is {age}");
}

In for loops

let pairs = vec![(1, 'a'), (2, 'b'), (3, 'c')];
 
for (number, letter) in &pairs {
    println!("{number}: {letter}");
}

With HashMap:

use std::collections::HashMap;
 
let mut map = HashMap::new();
map.insert("one", 1);
map.insert("two", 2);
 
for (key, value) in &map {
    println!("{key} = {value}");
}

Nested destructuring

Patterns can be nested as deeply as needed:

let ((feet, inches), Point { x, y }) = ((6, 1), Point { x: 3, y: 10 });

if let and while let

Destructure while conditionally matching:

if let Some((x, y)) = get_point() {
    println!("{x}, {y}");
}
 
while let Some(top) = stack.pop() {
    println!("{top}");
}