Rust Pattern Matching

What is Pattern Matching?

Pattern matching in Rust is a mechanism to compare a value against a series of patterns and execute code based on the first pattern that matches. It is primarily achieved using the match and if let constructs.

  • match: A comprehensive tool for pattern matching.
  • if let: A shorthand for simpler cases.

The Syntax of Pattern Matching

Basic Syntax of match:

match value {
pattern1 => action1,
pattern2 => action2,
_ => default_action,
}
  • value: The value being matched.
  • pattern: The pattern to match against.
  • action: The code executed if the pattern matches.
  • _: A catch-all pattern for unmatched cases.

Examples of Pattern Matching

1. Basic Match

fn main() {
let number = 2;

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

Output:

Two

2. Matching with Ranges

You can match numeric ranges using . .=.

fn main() {
let number = 15;

match number {
1..=10 => println!("Between 1 and 10"),
11..=20 => println!("Between 11 and 20"),
_ => println!("Outside the range"),
}
}

Output:

Between 11 and 20

3. Matching Enums

Enums are a natural fit for pattern matching.

enum TrafficLight {
Red,
Yellow,
Green,
}

fn main() {
let light = TrafficLight::Green;

match light {
TrafficLight::Red => println!("Stop!"),
TrafficLight::Yellow => println!("Get ready to move."),
TrafficLight::Green => println!("Go!"),
}
}

Output:

Go!

4. Matching with Tuples

Tuples can also be destructured using patterns.

fn main() {
let coordinates = (3, 7);

match coordinates {
(0, 0) => println!("Origin"),
(x, 0) => println!("Point on X-axis at {}", x),
(0, y) => println!("Point on Y-axis at {}", y),
(x, y) => println!("Point at ({}, {})", x, y),
}
}

Output:

Point at (3, 7)

5. Ignoring Values with _

The _ pattern matches any value and can be used to ignore values.

fn main() {
let data = (10, 20);

match data {
(x, _) => println!("First value is {}", x),
}
}

Output:

First value is 10

6. Destructuring Structs

Pattern matching can destructure structs to access their fields.

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

fn main() {
let point = Point { x: 5, y: 10 };

match point {
Point { x, y: 0 } => println!("Point on X-axis at {}", x),
Point { x: 0, y } => println!("Point on Y-axis at {}", y),
Point { x, y } => println!("Point at ({}, {})", x, y),
}
}

Output:

Point at (5, 10)

7. Using Guards in Patterns

You can add conditions to patterns with guards.

fn main() {
let number = 15;

match number {
n if n % 2 == 0 => println!("Even number: {}", n),
n if n % 2 != 0 => println!("Odd number: {}", n),
_ => println!("No match"),
}
}

Output:

Odd number: 15

Using if let for Simpler Matches

When only one pattern needs to be matched, if let can simplify your code.

fn main() {
let number = Some(5);

if let Some(value) = number {
println!("The value is {}", value);
} else {
println!("No value");
}
}

Output:

The value is 5

Advanced Concepts in Pattern Matching

1. Combining Patterns with |

You can match multiple patterns with a single arm using |.

fn main() {
let number = 1;

match number {
1 | 2 | 3 => println!("Matched 1, 2, or 3"),
_ => println!("No match"),
}
}

Output:

Matched 1, 2, or 3

2. Nested Patterns

Patterns can be nested for complex data structures.

enum Vehicle {
Car { brand: String, year: u32 },
Bike { model: String },
}

fn main() {
let vehicle = Vehicle::Car {
brand: String::from("Toyota"),
year: 2021,
};

match vehicle {
Vehicle::Car { brand, year } => println!("Car: {}, Year: {}", brand, year),
Vehicle::Bike { model } => println!("Bike: {}", model),
}
}

Output:

Car: Toyota, Year: 2021

Leave a Comment

BoxofLearn