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