使用 if let 的简洁控制流

if let 语法允许您将 iflet 组合起来,以一种更简洁的方式处理匹配一个模式的值,而忽略其余的值。考虑清单 6-6 中的程序,该程序匹配 config_max 变量中的 Option<u8> 值,但只想在值为 Some 变体时执行代码。

fn main() {
    let config_max = Some(3u8);
    match config_max {
        Some(max) => println!("The maximum is configured to be {max}"),
        _ => (),
    }
}

清单 6-6:一个仅在值为 Some 时才关心执行代码的 match

如果值为 Some,我们将通过在模式中将值绑定到变量 max 来打印 Some 变体中的值。我们不想对 None 值做任何事情。为了满足 match 表达式,我们必须在只处理一个变体后添加 _ => (),这是要添加的令人烦恼的样板代码。

相反,我们可以使用 if let 以更短的方式编写此代码。以下代码的行为与清单 6-6 中的 match 相同

fn main() {
    let config_max = Some(3u8);
    if let Some(max) = config_max {
        println!("The maximum is configured to be {max}");
    }
}

if let 语法采用一个模式和一个用等号分隔的表达式。它的工作方式与 match 相同,其中表达式被赋予 match,而模式是它的第一个分支。在这种情况下,模式是 Some(max),而 max 绑定到 Some 内部的值。然后,我们可以在 if let 块的主体中使用 max,就像我们在相应的 match 分支中使用 max 一样。如果该值与模式不匹配,则不会运行 if let 块中的代码。

使用 if let 意味着更少的键入、更少的缩进和更少的样板代码。但是,您会失去 match 强制执行的详尽检查。在 matchif let 之间进行选择取决于您在特定情况下所做的事情,以及为了获得简洁性而放弃详尽检查是否是适当的权衡。

换句话说,您可以将 if let 视为 match 的语法糖,当该值匹配一个模式时运行代码,然后忽略所有其他值。

我们可以在 if let 中包含 else。与 else 一起使用的代码块与与 match 表达式中等效于 if letelse_ 情况一起使用的代码块相同。回想一下清单 6-4 中的 Coin 枚举定义,其中 Quarter 变体还持有 UsState 值。如果我们想计算我们看到的所有非四分之一硬币,同时还公布四分之一硬币的状态,我们可以使用 match 表达式来完成,就像这样

#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn main() {
    let coin = Coin::Penny;
    let mut count = 0;
    match coin {
        Coin::Quarter(state) => println!("State quarter from {state:?}!"),
        _ => count += 1,
    }
}

或者我们可以使用 if letelse 表达式,就像这样

#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn main() {
    let coin = Coin::Penny;
    let mut count = 0;
    if let Coin::Quarter(state) = coin {
        println!("State quarter from {state:?}!");
    } else {
        count += 1;
    }
}

如果您的程序中有一些逻辑过于冗长而无法使用 match 表示,请记住 if let 也是您 Rust 工具箱中的一部分。

总结

我们现在已经介绍了如何使用枚举来创建自定义类型,该类型可以是一组枚举值之一。我们已经展示了标准库的 Option<T> 类型如何帮助您使用类型系统来防止错误。当枚举值内部有数据时,您可以根据需要处理多少种情况,使用 matchif let 来提取和使用这些值。

您的 Rust 程序现在可以使用结构体和枚举来表达您领域中的概念。创建要在您的 API 中使用的自定义类型可确保类型安全:编译器将确保您的函数仅获得每个函数期望的类型的值。

为了向您的用户提供组织良好的 API,该 API 易于使用并且仅公开您的用户真正需要的内容,现在让我们转到 Rust 的模块。