if let
在一些场合下,用 match 匹配枚举类型并不优雅。比如:
1. // 将 `optional` 定为 `Option<i32>` 类型
2. let optional = Some(7);
4. match optional {
5. Some(i) => {
6. println!("This is a really long string and `{:?}`", i);
7. // ^ 行首需要 2 层缩进。这里从 optional 中解构出 `i`。
8. // 译注:正确的缩进是好的,但并不是 “不缩进就不能运行” 这个意思。
9. },
10. _ => {},
11. // ^ 必须有,因为 `match` 需要覆盖全部情况。不觉得这行很多余吗?
12. };
if let 在这样的场合要简洁得多,并且允许指明数种失败情形下的选项:
1. fn main() {
2. // 全部都是 `Option<i32>` 类型
3. let number = Some(7);
4. let letter: Option<i32> = None;
5. let emoticon: Option<i32> = None;
7. // `if let` 结构读作:若 `let` 将 `number` 解构成 `Some(i)`,则执行
8. // 语句块(`{}`)
9. if let Some(i) = number {
10. println!("Matched {:?}!", i);
11. }
13. // 如果要指明失败情形,就使用 else:
14. if let Some(i) = letter {
15. println!("Matched {:?}!", i);
16. } else {
17. // 解构失败。切换到失败情形。
18. println!("Didn't match a number. Let's go with a letter!");
19. };
21. // 提供另一种失败情况下的条件。
22. let i_like_letters = false;
24. if let Some(i) = emoticon {
25. println!("Matched {:?}!", i);
26. // 解构失败。使用 `else if` 来判断是否满足上面提供的条件。
27. } else if i_like_letters {
28. println!("Didn't match a number. Let's go with a letter!");
29. } else {
30. // 条件的值为 false。于是以下是默认的分支:
31. println!("I don't like letters. Let's go with an emoticon :)!");
32. };
33. }
同样,可以用 if let 匹配任何枚举值:
1. // 以这个 enum 类型为例
2. enum Foo {
3. Bar,
4. Baz,
5. Qux(u32)
6. }
8. fn main() {
9. // 创建变量
10. let a = Foo::Bar;
11. let b = Foo::Baz;
12. let c = Foo::Qux(100);
14. // 变量 a 匹配到了 Foo::Bar
15. if let Foo::Bar = a {
16. println!("a is foobar");
17. }
19. // 变量 b 没有匹配到 Foo::Bar,因此什么也不会打印。
20. if let Foo::Bar = b {
21. println!("b is foobar");
22. }
24. // 变量 c 匹配到了 Foo::Qux,它带有一个值,就和上面例子中的 Some() 类似。
25. if let Foo::Qux(value) = c {
26. println!("c is {}", value);
27. }
28. }
另一个好处是:if let 允许匹配枚举非参数化的变量,即枚举未注明 #[derive(PartialEq)],我们也没有为其实现 PartialEq。在这种情况下,通常 if Foo::Bar==a 会出错,因为此类枚举的实例不具有可比性。但是,if let 是可行的。
你想挑战一下吗?使用 if let修复以下示例:
1. // 该枚举故意未注明 `#[derive(PartialEq)]`,
2. // 并且也没为其实现 `PartialEq`。这就是为什么下面比较 `Foo::Bar==a` 会失败的原因。
3. enum Foo {Bar}
5. fn main() {
6. let a = Foo::Bar;
8. // 变量匹配 Foo::Bar
9. if Foo::Bar == a {
10. // ^-- 这就是编译时发现的错误。使用 `if let` 来替换它。
11. println!("a is foobar");
12. }
13. }
