与C相比,Rust多了if let和while let这两个流程控制语句,因为之前我没有接触过这种,因此第一感觉就是有点抽象。
if let语句
先来看个具体的场景:
代码语言:javascript复制// Make `optional` of type `Option<i32>`
let optional = Some(7);
match optional {
Some(i) => {
println!("This is a really long string and `{:?}`", i);
},
_ => {},
};
对于上面这个“只需要匹配一个分支”的场景,我们想要当optional变量为Some的时候,执行一些操作。为了实现这样的目标,我们引入了match语句。而match语句要求我们必须为其他情况编写一个处理分支,这显得不是那么的雅观。if let语句的引入正是为了改善上述代码的整洁度。
使用if let语句后,可以将上述代码等价转换为:
代码语言:javascript复制if let Some(i) = optional {
println!("This is a really long string and `{:?}`", i);
}
其中,上述if let语句读作:“若 let
将 optional
解构成 Some(i)
,则执行{}中的代码”。
仔细对比就可以发现,if let其实就是相当于match的简化版,它只匹配一个分支,当匹配条件不满足的时候,就不执行后面的{}中的代码。这样,我们就不用编写一个match语句了,使得代码更加整洁。
对于匹配失败的情况,我们允许在if let语句后面跟上一个else,当匹配失败时,将执行else的内容。其实就是相当于最开始的 _=> {} 分支。
代码语言:javascript复制if let Some(i) = optional {
println!("This is a really long string and `{:?}`", i);
}else{
println!("failed.");
}
while let语句
与if let类似,while let语句解决的是下面这个“循环匹配一个分支“的场景中,match语句带来的复杂性的问题。
代码语言:javascript复制// 将 `optional` 设为 `Option<i32>` 类型
let mut optional = Some(0);
// 重复运行这个测试
loop {
match optional {
// 如果 `optional` 解构成功,就执行下面语句块。
Some(i) => {
if i > 9 {
println!("Greater than 9, quit!");
optional = None;
} else {
println!("`i` is `{:?}`. Try again.", i);
optional = Some(i 1);
}
// ^ 需要三层缩进!
},
// 当解构失败时退出循环:
_ => { break; }
}
}
上面的代码需要三层的缩进,看起来不是那么美观。由于我们只是想循环的匹配optional变量是Some(i)的这个种情况,在这里写loop{match{}}就有点大材小用了。
上述代码可以等价的转换为:
代码语言:javascript复制let mut optional = Some(0);
while let Some(i) = optional {
if i > 9 {
println!("Greater than 9, quit!");
optional = None;
} else {
println!("`i` is `{:?}`. Try again.", i);
optional = Some(i 1);
}
}
上述while let读作“只要let能
将 optional
解构成 Some(i)
,则执行{}中的代码,直到optional不再能被解构成Some(i)为止”。所以,while let语句其实就是相当于只有一个待匹配分支的loop{match{}}语句块的功能。
参考资料:
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html