src/pattern-matching/match.md
The match keyword lets you match a value against one or more patterns. The
patterns can be simple values, similarly to switch in C and C++, but they can
also be used to express more complex conditions:
# // Copyright 2024 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
#[rustfmt::skip]
fn main() {
let input = 'x';
match input {
'q' => println!("Quitting"),
'a' | 's' | 'w' | 'd' => println!("Moving around"),
'0'..='9' => println!("Number input"),
key if key.is_lowercase() => println!("Lowercase: {key}"),
_ => println!("Something else"),
}
}
A variable in the pattern (key in this example) will create a binding that can
be used within the match arm. We will learn more about this on the next slide.
A match guard causes the arm to match only if the condition is true. If the condition is false the match will continue checking later cases.
<details>Key Points:
You might point out how some specific characters are being used when in a pattern
| as an or.. matches any number of items1..=5 represents an inclusive range_ is a wild cardMatch guards as a separate syntax feature are important and necessary when we wish to concisely express more complex ideas than patterns alone would allow.
Match guards are different from if expressions after the =>. An if
expression is evaluated after the match arm is selected. Failing the if
condition inside of that block won't result in other arms of the original
match expression being considered. In the following example, the wildcard
pattern _ => is never even attempted.
# // Copyright 2024 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
#[rustfmt::skip]
fn main() {
let input = 'a';
match input {
key if key.is_uppercase() => println!("Uppercase"),
key => if input == 'q' { println!("Quitting") },
_ => println!("Bug: this is never printed"),
}
}
|.# // Copyright 2024 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
let expected = 5;
match 123 {
expected => println!("Expected value is 5, actual is {expected}"),
_ => println!("Value was something else"),
}
Another piece of pattern syntax you can show students is the @ syntax which
binds a part of a pattern to a variable. For example:
# // Copyright 2024 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
let opt = Some(123);
match opt {
outer @ Some(inner) => {
println!("outer: {outer:?}, inner: {inner}");
}
None => {}
}
In this example inner has the value 123 which it pulled from the Option
via destructuring, outer captures the entire Some(inner) expression, so it
contains the full Option::Some(123). This is rarely used but can be useful
in more complex patterns.