3.6 KiB
if let
简单控制流
ch06-03-if-let.md
commit 3f2a1bd8dbb19cc48b210fc4fb35c305c8d81b56
if let
语法让我们以一种不那么冗长的方式结合if
和let
,来处理匹配一个模式的值而忽略其他的值。考虑列表 6-6 中的程序,它匹配一个Option<u8>
值并只希望当值是三时执行代码:
let some_u8_value = Some(0u8);
match some_u8_value {
Some(3) => println!("three"),
_ => (),
}
Listing 6-6: A match
that only cares about executing
code when the value is Some(3)
我们想要对Some(3)
匹配进行操作不过不想处理任何其他Some<u8>
值或None
值。为了满足match
表达式(穷尽性)的要求,必须在处理完这唯一的成员后加上_ => ()
,这样也要增加很多样板代码。
不过我们可以使用if let
这种更短的方式编写。如下代码与列表 6-6 中的match
行为一致:
# let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
}
if let
获取通过=
分隔的一个模式和一个表达式。它的工作方式与match
相同,这里的表达式对应match
而模式则对应第一个分支。
使用if let
意味着编写更少代码,更少的缩进和更少的样板代码。然而,这样会失去match
强制要求的穷尽性检查。match
和if let
之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。
换句话说,可以认为if let
是match
的一个语法糖,它当值匹配某一模式时执行代码而忽略所有其他值。
可以在if let
中包含一个else
。else
块中的代码与match
表达式中的_
分支块中的代码相同,这样的match
表达式就等同于if let
和else
。回忆一下列表 6-4 中Coin
枚举的定义,它的Quarter
成员包含一个UsState
值。如果想要计数所有不是 25 美分的硬币的同时也报告 25 美分硬币所属的州,可以使用这样一个match
表达式:
# #[derive(Debug)]
# enum UsState {
# Alabama,
# Alaska,
# }
#
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter(UsState),
# }
# 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,
# }
#
# enum Coin {
# Penny,
# Nickel,
# Dime,
# Quarter(UsState),
# }
# 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 的模块系统吧。