match
match 是一个极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成。
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
绑定值的模式
在匹配到绑定值的模式后,可以增加一个变量用来表示所匹配到的值。
#[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
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 可能会提示我们有更好的写法:
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 。
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => (),
}
这个例子也满足穷举性要求,因为我们在最后一个分支中明确地忽略了其他的值。我们没有忘记处理任何东西。
if let
为了满足 match 的穷尽性的要求,必须穷举到所有的可能性。尽管可以使用默认操作,但是最少也需要两行语句。
fn main() {
let config_max = Some(3u8);
match config_max {
Some(config) => println!("The maximum is configured to be {}", config),
_ => (),
}
}
不过我们可以使用 if let 这种更短的方式编写。
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 的一个语法糖,它当值匹配某一模式时执行代码而忽略所有其他值。