Skip to main content
โšก Calmops

Rust's Match Usage

Rust’s match expression is a powerful control flow construct that allows for pattern matching against values. It’s similar to switch statements in other languages but much more expressive, enabling destructuring, guards, and exhaustive checking.

Basic Syntax

The match expression evaluates an expression and compares its value against a series of patterns. Each pattern is followed by a => and a block of code to execute if the pattern matches.

let number = 5;

match number {
    1 => println!("One"),
    2 => println!("Two"),
    3 => println!("Three"),
    _ => println!("Something else"),
}

Patterns

Literals

Match against specific values:

let x = 1;

match x {
    1 => println!("One"),
    2 => println!("Two"),
    3 => println!("Three"),
    _ => println!("Other"),
}

Variables

Bind the matched value to a variable:

let x = 5;

match x {
    n => println!("Got {}", n),
}

Wildcard

The _ pattern matches anything and ignores the value:

let x = Some(5);

match x {
    Some(_) => println!("Got some value"),
    None => println!("Got nothing"),
}

Multiple Patterns

Use | to match multiple patterns:

let x = 1;

match x {
    1 | 2 | 3 => println!("Small number"),
    4 | 5 | 6 => println!("Medium number"),
    _ => println!("Large number"),
}

Matching on Enums

Enums are commonly used with match:

enum Color {
    Red,
    Green,
    Blue,
}

let color = Color::Red;

match color {
    Color::Red => println!("Red"),
    Color::Green => println!("Green"),
    Color::Blue => println!("Blue"),
}

For enums with data:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

let msg = Message::Move { x: 10, y: 20 };

match msg {
    Message::Quit => println!("Quit"),
    Message::Move { x, y } => println!("Move to ({}, {})", x, y),
    Message::Write(text) => println!("Text: {}", text),
    Message::ChangeColor(r, g, b) => println!("Color: ({}, {}, {})", r, g, b),
}

Matching on Structs

struct Point {
    x: i32,
    y: i32,
}

let point = Point { x: 10, y: 20 };

match point {
    Point { x: 0, y: 0 } => println!("Origin"),
    Point { x, y: 0 } => println!("On x-axis at {}", x),
    Point { x: 0, y } => println!("On y-axis at {}", y),
    Point { x, y } => println!("At ({}, {})", x, y),
}

Matching on Tuples

let tuple = (1, 2, 3);

match tuple {
    (0, y, z) => println!("First is 0, y={}, z={}", y, z),
    (1, ..) => println!("First is 1, rest ignored"),
    _ => println!("Something else"),
}

Guards

Add conditions to patterns with if:

let num = Some(4);

match num {
    Some(x) if x < 5 => println!("Less than five: {}", x),
    Some(x) => println!("Five or more: {}", x),
    None => println!("None"),
}

Exhaustiveness

Rust requires that match expressions be exhaustive - all possible values must be covered. The _ pattern is often used as a catch-all.

Binding with @

Use @ to bind a value while also testing it:

let msg = Message::Write(String::from("hello"));

match msg {
    Message::Write(s @ String::from("hello")) => println!("Hello: {}", s),
    Message::Write(s) => println!("Other: {}", s),
    _ => (),
}

Match as Expression

match returns a value, so it can be used in assignments:

let result = match x {
    1 => "one",
    2 => "two",
    _ => "other",
};

Advanced Patterns

References

let x = &Some(5);

match x {
    &Some(n) => println!("Got {}", n),
    &None => println!("None"),
}

Slices

let v = vec![1, 2, 3, 4, 5];

match v.as_slice() {
    [first, second, ..] => println!("First: {}, Second: {}", first, second),
    [single] => println!("Single: {}", single),
    [] => println!("Empty"),
    _ => println!("Many elements"),
}

Best Practices

  1. Use match for exhaustive checking of enum variants.
  2. Prefer if let for simple single-pattern matches.
  3. Use guards sparingly to keep patterns readable.
  4. Leverage destructuring to extract data directly in patterns.

Conclusion

Rust’s match expression is a cornerstone of idiomatic Rust code, providing safe and expressive pattern matching. Mastering match allows you to write more robust and readable code, especially when working with enums and complex data structures.

For more advanced topics, explore the Rust documentation on pattern matching and consider using matches! macro for simple boolean checks.

Comments