6.3.1. What Is match?
match allows a value to be compared against a series of patterns and executes the code corresponding to the matching pattern. Patterns can be literals, variable names, wildcards, and more.
Think of a match expression as a coin-sorting machine: coins slide down a track with holes of different sizes, and each coin falls through the first hole that fits it. In the same way, a value goes through each pattern in match, and when it “fits” the first pattern, it falls into the associated code block that will be used during execution.
6.3.2. Practical Use of match
Let’s look at an example: write a function that takes an unknown U.S. coin and determines which coin it is in a counting-machine-like way, then returns its value in cents.
enum Coin {
Penny,// 1 cent
Nickel,// 5 cents
Dime,// 10 cents
Quarter,// 25 cents
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
The
matchkeyword is followed by an expression, which in this example is the valuecoin. This looks very similar to the conditional expression used inif, but there is one big difference: the condition ofifmust be a boolean value, whilematchcan work with any type. In this example, the type ofcoinis theCoinenum we defined in the first line.Next comes the braces. Inside the braces there are four branches (also called arms), and each branch is made up of a pattern to match and the code corresponding to that pattern. The first branch,
Coin::Penny => 1,, usesCoin::Pennyas its pattern. The=>separates the pattern from the code to run, and here the code to run is the value1, meaning it returns1. Different branches are separated by commas.When a
matchexpression runs, it compares the expression aftermatch—here,coin—with the branches inside from top to bottom. If a pattern matches the value, the code associated with that pattern runs. If it does not match, the next branch is checked. The code expression corresponding to the successful branch is returned as the value of the entirematchexpression.
For example, ifmatchmatches a 5-cent coin, that is,Coin::Nickel, then the whole expression evaluates to5. And because thematchexpression is the last expression invalue_in_cents, its value—5—is returned by the function.Here each branch’s code is very simple, so
=>is enough. But if one branch contains multiple lines of code, you need to wrap those lines in braces. For example:
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
6.3.3. Patterns That Bind Values
Branches in a match can bind to part of the matched value, allowing you to extract values from enum variants.
For example, a friend is trying to collect all 50 state quarters. When we sort change by coin type, we also label the state name associated with each quarter (there are too many U.S. states, so only Alabama and Alaska are shown here):
#[derive(Debug)] // For easier debug printing
enum UsState {
Alabama,
Alaska,
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
}
}
}
fn main() {
let c = Coin::Quarter(UsState::Alaska);
println!("{}", value_in_cents(c));
}
Give the
Coinvariant for a quarter coin a piece of associated data, namely theUsStateenum above.In the
value_in_centsfunction, theQuarterbranch also needs to be adjusted. The match pattern changes fromCoin::QuartertoCoin::Quarter(state), which means the value associated withCoin::Quarteris bound to the variablestate, so it can be used in the following block to access that associated value.
In some situations, the value associated withCoin::Quartermay not be needed. In that case, you can use the wildcard_to indicate that you do not care about the contents:Coin::Quarter(_)In
main, a variablecis declared first, holdingCoin::Quarter(UsState::Alaska). In other words, it stores theCoin::Quartervariant and its associated value is theUsState::Alaskavariant. Thenvalue_in_centsis called.
Let’s look at the output:
State quarter from Alaska!
25
6.3.4. Matching Option<T>
Let’s analyze the last code example from the previous article:
fn main() {
let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = match y {
Some(value) => x + value, // If y is Some, unwrap it and add
None => x, // If y is None, return x
};
}
- If
yis notNone, unwrap it, bind the value associated withSometovalue, and returnx + value. - If
yisNone, return only the value ofx.
6.3.5. match Must Be Exhaustive
Rust requires match to cover all possibilities so that code remains safe and valid.
Make a small modification to the previous code:
fn main() {
let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = match y {
Some(value) => x + value,
};
}
Output:
error[E0004]: non-exhaustive patterns: `None` not covered
--> src/main.rs:5:21
|
5 | let sum = match y {
| ^ pattern `None` not covered
|
note: `Option<i8>` defined here
--> /Users/stanyin/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:571:1
|
571 | pub enum Option<T> {
| ^^^^^^^^^^^^^^^^^^
...
575 | None,
| ---- not covered
= note: the matched value is of type `Option<i8>`
help: ensure that all possible cases are handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
6 ~ Some(value) => x + value,
7 ~ None => todo!(),
|
Rust detected that the possibility of None was not covered, so it reported an error. Once you add a branch to handle None, everything is fine.
If there are too many possibilities or you do not want to handle some of them, you can use the wildcard _.
6.3.6. Wildcards
First write the branches you want to handle as usual, and use the wildcard _ for everything else.
For example: v is a u8 variable, and we want to determine whether v is 0.
use rand::Rng; // Use an external crate
fn main(){
let v: u8 = rand::thread_rng().gen_range(0..=255); // Generate a random number
println!("{}", v);
match v {
0 => println!("zero"),
_ => println!("not zero"),
}
}
u8 has 256 possible values, so it is naturally impossible to write one branch for each value using match. Therefore, you can write a branch for 0 and use the wildcard _ for everything else.
Output:
136
not zero
Top comments (0)