使用 if let 的简洁控制流
if let 语法允许你将 if 和 let 结合起来,以一种更简洁的方式处理匹配一个模式的值,同时忽略其余的值。考虑示例 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:一个 match,只关心在值为 Some 时执行代码
如果值是 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 强制执行的穷尽检查。在 match 和 if let 之间进行选择取决于你在特定情况下正在做什么,以及为了获得简洁性而牺牲穷尽检查是否是合适的权衡。
换句话说,你可以将 if let 视为 match 的语法糖,它在值匹配一个模式时运行代码,然后忽略所有其他值。
我们可以在 if let 中包含一个 else。与 else 一起使用的代码块与 match 表达式中与 _ 情况一起使用的代码块相同,该表达式等效于 if let 和 else。回想一下示例 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 let 和 else 表达式,如下所示
#[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> 类型如何帮助你使用类型系统来防止错误。当枚举值内部有数据时,你可以使用 match 或 if let 来提取和使用这些值,具体取决于你需要处理多少种情况。
你的 Rust 程序现在可以使用结构体和枚举来表达你领域中的概念。创建自定义类型以在你的 API 中使用可确保类型安全:编译器将确保你的函数仅获取每个函数期望的类型的值。
为了向你的用户提供组织良好、易于使用且仅公开用户真正需要的 API,现在让我们转向 Rust 的模块。