Appearance
7.3 if-let 和 while-let
Rust 不仅能在 match 表达式中执行“模式解构”,在 let 语句中,也可以应用同样的模式。Rust 还提供了 if-let 语法糖。它的语法为if let PATTERN = EXPRESSION{ BODY }
。后面可以跟一个可选的 else 分支。
比如,我们有一个类型为Option<T>
的变量optVal
,如果我们需要取出里面的值,可以采用这种方式:
rust
match optVal {
Some(x) => {
doSomethingWith(x);
}
_ => {}
}
这样做语法比较冗长,从变量optVal
到执行操作的函数有两层缩进,我们还必须写一个不做任何操作的语句块才能满足语法要求。换一种方式,通过 Option 类型的方法,我们可以这么做:
rust
if optVal.is_some() { // 首先判断它一定是 Some(_)
let x = optVal.unwrap(); // 然后取出内部的数据
doSomethingWith(x);
}
从视觉上来看,代码缩进层次减少到了一层。但是它在运行期实际上判断了两次optVal
里面是否有值:第一次是is_some()
函数,第二次是unwrap()
函数。从执行效率上来说是降低了的。而使用 if-let 语法,则可以这么做:
rust
if let Some(x) = optVal {
doSomethingWith(x);
}
这其实是一个简单的语法糖,其背后执行的代码与 match 表达式相比,并无效率上的差别。它跟 match 的区别是:match 一定要完整匹配,if-let 只匹配感兴趣的某个特定的分支,这种情况下的写法比 match 简单点。同理,while-let 与 if-let 一样,提供了在 while 语句中使用“模式解构”的能力,此处就不再举例。
if-let 和 while-let 还支持模式的“或”操作(此功能目前尚未在编译器中实现)。比如,我们有如下 enum 定义:
rust
enum E<T> {
A(T), B(T), C, D, E, F
}
如果我们需要匹配C
或者D
,那么可以这样写:
rust
let r = if let C | D = x { 1 } else { 2 };
这段代码等同于:
rust
let r = match x {
C | D => 1,
_ => 2,
}
在这个匹配过程中还可以有变量绑定,比如:
rust
if let A(x) | B(x) = expr {
do_something(x);
}
这段代码等同于:
rust
match expr {
A(x) | B(x) => do_something(x),
_ => {},
}