Files
DefectingCat.github.io/content/posts/rust-pattern-matching.mdx
xfy b730b44f10 update new posts
rust-box-and-object
rust-pattern-matching
2024-10-24 09:13:56 +08:00

143 lines
3.6 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Rust 模式匹配
date: '2023-02-07'
tags: [Rust]
---
## match
`match` 是一个极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成。
```rust
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
```
### 绑定值的模式
在匹配到绑定值的模式后,可以增加一个变量用来表示所匹配到的值。
```rust
#[derive(Debug)] // 这样可以立刻看到州的名称
enum UsState {
Alabama,
Alaska,
// --snip--
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
}
}
}
```
这里的 `Coin::Quarter(state)` 就是匹配到的对应的 `UsState` 的值。
### 匹配 Option
```rust
fn plus_one(target: Option<i32>) -> Option<i32> {
match target {
Some(x) => Some(x + 1),
None => None,
}
}
fn main() {
let my_num = Some(41);
let my_num = plus_one(my_num);
println!("My number: {:?}", my_num);
}
```
这里 Clippy 可能会提示我们有更好的写法:
```rust
fn plus_one(target: Option<i32>) -> Option<i32> {
target.map(|x| x + 1);
target
}
fn main() {
let my_num = Some(41);
let my_num = plus_one(my_num);
println!("My number: {:?}", my_num);
}
```
`Option<T>` 上有个 `map()` 方法,可以更好的代替 `match Option` 来做匹配。
### 穷尽的匹配
`match` 的匹配是穷尽的,必须穷举到最后的可能性来使代码有效。
但可以使用一个特定值来采取默认操作,有点类似于 `switch` 语句中的 `default` 。
```rust
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => (),
}
```
这个例子也满足穷举性要求,因为我们在最后一个分支中明确地忽略了其他的值。我们没有忘记处理任何东西。
## if let
为了满足 `match` 的穷尽性的要求,必须穷举到所有的可能性。尽管可以使用默认操作,但是最少也需要两行语句。
```rust
fn main() {
let config_max = Some(3u8);
match config_max {
Some(config) => println!("The maximum is configured to be {}", config),
_ => (),
}
}
```
不过我们可以使用 `if let` 这种更短的方式编写。
```rust
fn main() {
let config_max = Some(3u8);
if let Some(config) = config_max {
println!("The maximum is configured to be {}", config);
}
}
```
如果使用了 Clippy 这里也会提示我们可以使用更短的写法。
`if let` 语法获取通过等号分割的一个模式和一个表达式。它的工作方式与 `match` 相同。这里等号右边的表达式对应着 `match` ,而左边的模式对应着 `match` 的第一个分支。
在这个例子中,模式是 `Some(max)``max` 绑定为 `Some` 中的值。接着可以在 `if let` 代码块中使用 `max` 了,就跟在对应的 `match` 分支中一样。模式不匹配时 `if let` 块中的代码不会执行。
换句话说,可以认为 `if let` 是 `match` 的一个语法糖,它当值匹配某一模式时执行代码而忽略所有其他值。