--- 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) -> Option { 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) -> Option { 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` 上有个 `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` 的一个语法糖,它当值匹配某一模式时执行代码而忽略所有其他值。