How to Use Pattern Matching In Rust?

13 minutes read

Pattern matching in Rust is a powerful feature that allows you to match and destructure data structures such as enums, structs, tuples, and slices. It is primarily used in match expressions, function and closure arguments, and the let statement.


To use pattern matching in Rust, you typically use the match expression. You specify the value you want to match on, followed by arms that contain patterns and code to execute when a match occurs. Each arm consists of a pattern, followed by the => symbol and the code to execute.


The patterns can be quite flexible and expressive. You can match on specific values, ranges of values, bind variables, ignore values, or even nest patterns. Rust also supports guards, which are additional boolean expressions that are evaluated alongside the pattern to provide more fine-grained control over matching.


Here is an example of using pattern matching to handle different types of data in a match expression:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
enum Element {
    Number(i32),
    Text(String),
    Other,
}

fn process_element(element: Element) {
    match element {
        Element::Number(n) => {
            println!("Received a number: {}", n);
        },
        Element::Text(s) => {
            println!("Received a text: {}", s);
        },
        Element::Other => {
            println!("Received something else");
        },
    }
}


In the above code, the process_element function takes an Element enum as an argument. The match expression is used to handle different variants of the enum. If the variant is Element::Number, the value inside is bound to the variable n, and the corresponding code is executed. Similarly, if it matches Element::Text, the value is bound to s, and the code is executed. The Element::Other case handles any other variant that is not explicitly matched.


Pattern matching can also be used to destructure tuples, slices, and structs. It allows you to extract individual elements or fields to perform further operations on them. Additionally, you can use the wildcard pattern _ to ignore values that you're not interested in.


Overall, pattern matching is a powerful tool in Rust that enables you to write concise and expressive code by handling different cases and data structures in a readable and efficient manner.

Top Rated Rust Books of July 2024

1
Programming Rust: Fast, Safe Systems Development

Rating is 5 out of 5

Programming Rust: Fast, Safe Systems Development

2
Rust in Action

Rating is 4.9 out of 5

Rust in Action

3
Programming Rust: Fast, Safe Systems Development

Rating is 4.8 out of 5

Programming Rust: Fast, Safe Systems Development

4
Hands-On Microservices with Rust: Build, test, and deploy scalable and reactive microservices with Rust 2018

Rating is 4.7 out of 5

Hands-On Microservices with Rust: Build, test, and deploy scalable and reactive microservices with Rust 2018

5
Programming WebAssembly with Rust: Unified Development for Web, Mobile, and Embedded Applications

Rating is 4.6 out of 5

Programming WebAssembly with Rust: Unified Development for Web, Mobile, and Embedded Applications

6
Rust for Rustaceans: Idiomatic Programming for Experienced Developers

Rating is 4.5 out of 5

Rust for Rustaceans: Idiomatic Programming for Experienced Developers

7
The Complete Rust Programming Reference Guide: Design, develop, and deploy effective software systems using the advanced constructs of Rust

Rating is 4.4 out of 5

The Complete Rust Programming Reference Guide: Design, develop, and deploy effective software systems using the advanced constructs of Rust

8
Beginning Rust Programming

Rating is 4.3 out of 5

Beginning Rust Programming

9
Beginning Rust: From Novice to Professional

Rating is 4.2 out of 5

Beginning Rust: From Novice to Professional

10
Systems Programming with Rust: A Project-Based Primer

Rating is 4.1 out of 5

Systems Programming with Rust: A Project-Based Primer


How to match against a range of values in Rust?

In Rust, you can use the match expression to match against a range of values using the ..= operator. Here's an example of how to do it:

1
2
3
4
5
6
7
8
9
fn main() {
    let number = 5;

    match number {
        1..=5 => println!("Number is between 1 and 5"),
        6..=10 => println!("Number is between 6 and 10"),
        _ => println!("Number is outside the range"),
    }
}


In this example, number is matched against different ranges using the ..= operator. The ..= operator represents an inclusive range, meaning both the start and end values are included in the range.


In the match arms, you can perform any action that you want based on the matched range. In this case, we're simply printing out a message indicating which range the number falls into.


The _ pattern in the last arm acts as a catch-all case for any value that doesn't match the specified ranges.


Note that the ..= operator can be used for various types that implement the PartialOrd trait, such as u32, f64, and others.


How to match against specific types in Rust?

In Rust, you can match against specific types using the match keyword and pattern matching. Here's how you can do it:

  1. Start by defining an enum that represents the different types you want to match against:
1
2
3
4
5
enum MyType {
    Type1(i32),
    Type2(f32),
    Type3(String),
}


  1. In your code, use the match keyword to match against specific types:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn process_type(my_type: MyType) {
    match my_type {
        MyType::Type1(value) => {
            // Process Type1 with i32 value
        }
        MyType::Type2(value) => {
            // Process Type2 with f32 value
        }
        MyType::Type3(value) => {
            // Process Type3 with String value
        }
    }
}


  1. Inside each arm of the match expression, you can perform the specific logic for that type.
  2. You can also use the _ wildcard pattern to match against any other type that is not explicitly handled:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
fn process_type(my_type: MyType) {
    match my_type {
        MyType::Type1(value) => {
            // Process Type1 with i32 value
        }
        MyType::Type2(value) => {
            // Process Type2 with f32 value
        }
        MyType::Type3(value) => {
            // Process Type3 with String value
        }
        _ => {
            // Handle any other type not explicitly matched
        }
    }
}


By using match and pattern matching, you can easily match against specific types in Rust and perform different operations based on the matched type.


What is a tuple pattern in Rust?

A tuple pattern in Rust is a pattern matching construct that allows developers to destructure a tuple into its individual elements. It is used in conjunction with the match expression or in function arguments to extract and bind specific values from a tuple.


The syntax of a tuple pattern involves enclosing the pattern in parentheses and separating the patterns for each element with commas. Here's an example:

1
2
3
4
5
6
7
8
9
fn main() {
    let tuple = (1, 2, 3);

    match tuple {
        (x, y, z) => {
            println!("x: {}, y: {}, z: {}", x, y, z);
        }
    }
}


In this example, the tuple (1, 2, 3) is matched against the pattern (x, y, z), allowing the values 1, 2, and 3 to be bound to the variables x, y, and z respectively. The code within the match arm will then be executed with access to these individual values.


Tuple patterns are useful for scenarios where the exact values of a tuple are not known in advance, but the developer wants to extract and work with specific elements of the tuple.


What is an irrefutable pattern in Rust?

An irrefutable pattern in Rust is a pattern that will always match. It means that the pattern will never fail to match the provided value. This is in contrast to a refutable pattern, which can fail to match certain values.


Examples of irrefutable patterns in Rust include:

  1. Binding a value to a variable using a simple identifier: let x = 5;
  2. Destructuring a tuple: let (x, y) = (1, 2);
  3. Ignoring a value using an underscore: let _ = 42;


In these cases, the patterns will always match the values being assigned or destructured, and thus they are considered irrefutable.


What is a pattern expression in Rust?

In Rust, a pattern expression is used to match the structure of input data and destructure it into its constituent parts. It is often used in conjunction with the match expression or function parameters for pattern matching.


Pattern expressions in Rust allow developers to specify different cases or conditions for handling different data structures. They help in extracting and assigning values to variables or in executing specific code blocks based on the shape or content of the data being matched.


Some examples of pattern expressions in Rust include:

  • Matching a literal value: match x { 0 => "zero", 1 => "one", _ => "other" }
  • Destructuring a tuple: let (x, y) = coordinates
  • Ignoring specific values: match point { (0, _) => "y-axis", (_, 0) => "x-axis", _ => "other" }
  • Using guards for additional conditions: match age { 0..=12 => "child", 13..=19 if is_student => "student", _ => "adult" }


Pattern expressions provide a flexible way to handle different cases and execute appropriate code blocks based on the input data's structure or contents. They play a significant role in idiomatic Rust programming and assist in writing robust and concise code.


What is a match binding in Rust?

A match binding in Rust is a feature that allows pattern matching and binding variables to values at the same time. In a match expression, you can use the match binding syntax to extract values from patterns and assign them to variables.


Typically, match bindings are used in combination with match arms, which are the individual patterns and their corresponding code blocks. When a match arm is matched against an input value, any variables that are bound within the pattern are assigned the corresponding values from the input.


Here's an example to illustrate the usage of match bindings:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

enum UsState {
    Alabama,
    Alaska,
    // ... other states
}

fn main() {
    let coin = Coin::Quarter(UsState::Alaska);

    match coin {
        Coin::Penny => {
            println!("It's a penny");
        }
        Coin::Nickel => {
            println!("It's a nickel");
        }
        Coin::Dime => {
            println!("It's a dime");
        }
        Coin::Quarter(state) => { // match binding
            println!("It's a quarter from {:?}", state);
        }
    }
}


In this example, the Coin::Quarter(state) pattern has a match binding. When the value Coin::Quarter(UsState::Alaska) matches this pattern, the value UsState::Alaska is bound to the variable state, which can then be used within the corresponding code block. In this case, it prints "It's a quarter from Alaska".

Facebook Twitter LinkedIn Whatsapp Pocket

Related Posts:

Pattern matching is a powerful feature in Rust that allows you to destructure complex data structures and perform different actions based on the pattern of the data.To use pattern matching in Rust, you can use the match keyword followed by a series of patterns...
Pattern matching is a powerful feature in Haskell that allows you to deconstruct data structures and extract values. It is used to define functions that behave differently based on the shape or contents of the input.Here is a general syntax for pattern matchin...
In MySQL, the LIKE operator is used for pattern matching in queries. It allows you to search for a specified pattern in a column. The % wildcard can be used in the LIKE operator to match any sequence of characters (including zero characters) in the pattern. Fo...