Skip to content

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),
    _ => {},
}

Released under the MIT License