Pattern matching is a very general operation in programming. In Rust, we can use the pattern-matching features to match the data structures such as enums, structs, tuples, etc, to specific patterns.
The match expression in Rust allows us to perform a concise and efficient pattern that matches with less code. This is because it removes the need for nested if/else and switch blocks. This makes it an exceptionally useful tool for any Rust developer.
This tutorial explores the fundamentals of working with Rust pattern matching expression including syntax, working with multiple patterns, and more.
Rust Match Expression
The match expression in Rust allows us to define a specific value and a set of patterns that we wish to match. If it matches a particular pattern, we execute a specific code block as defined in the following syntax:
pattern1 => expression1,
pattern2 => expression2,
pattern3 => expression3,
// ...
}
We start with the match keyword and open the pattern matching block to use the match expression. Then, inside the match block, we define the list of patterns and the expressions that we wish to execute if any pattern matches.
If none of the defined patterns match the expression, Rust throws a runtime error and exits the match block.
Rust Literal Patterns
The first type of pattern that we can match is a literal pattern. These pattern types allow us to match a specific value to a set of options. We can use these patterns with any data type that implements the PartialEq trait.
Example:
let name = "Alice";
match name {
"Alice" => println!("Hello, Alice!"),
"Bob" => println!("Hello, Bob!"),
_ => println!("Hello, stranger!"),
}
}
In the provided example, we use the match expression to match the value of the name variable to two options. We execute the corresponding message if any pattern matches.
We also use the “_” pattern to catch all cases in case none of the defined patterns matches the expression.
Rust Variable Patterns
Variable patterns allow us to bind a variable to the value that the pattern matches. An example is as follows:
let x = 10;
match x {
val => println!("x is {}", val),
}
}
In this case, the variable val is bound to the value of x which is 10.
Rust Struct Patterns
Rust also allows us to use the match expression to perform a pattern search against a struct field. An example is as follows:
struct Point {
x: i32,
y: i32,
}
let point = Point { x: 3, y: 2 };
match point {
Point { x, y } => println!("({},{})", x, y),
}
}
In this case, we match the “Point” struct against a pattern set that binds the values of x and y to the variables.
This should return the following value:
Rust Enum Patterns
Enum patterns allow us to match against the variants of an enum. An example demonstration is as follows:
enum Color {
Red,
Blue,
Green,
}
let color = Color::Blue;
match color {
Color::Red => println!("The color is Red!"),
Color::Blue => println!("The color is Blue!"),
Color::Green => println!("The color is Green!"),
}
}
This should match the color and return the corresponding value as follows:
Rust Match on References
We can also match on references using the “ref” keyword. An example demonstration is as follows:
let value = 10;
match &value {
&val => println!("The value is {}", val),
}
}
In this case, the & symbol before the value allows us to create a reference to the value. Hence, using thre “ref” keword in the pattern, we bind the value to the val variable which allows us to access the original value via the reference.
Rust Match Guards
In Rust, guards refers to Boolean expressions that can be added to patterns to further filter the matches. Consider the following example demonstration:
let number = Some(7);
match number {
Some(x) if x < 5 => println!("Less than 5: {}", x),
Some(x) => println!("Greater than or equal to 5: {}", x),
None => (),
}
}
In this case, we match the variable number against some variant of the option enum. The first pattern checks if the value of x is less than 5 against a guard. The second pattern matches any other value.
Output:
The “_” Placeholder
If we do not wish to match any specific value, we can use the “_” as a placeholder. For example, we can use it to capture all other patterns that do not check the defined set.
Example:
let number = 10;
match number {
10 => println!("Ten"),
20 => println!("Twenty"),
_ => println!("Other"),
}
}
This should allow you to capture any other case that does not match.
Conclusion
We explored the fundamentals of pattern matching in the Rust programming language by learning about the match expression. This expression allows us to define a set of patterns against which we wish to compare and perform an appropriate message if any matches.