Rust 流程控制IF

if-else 分支判断和其他语言类似。不同的是,Rust 语言中的布尔判断条件不必使用小括号包裹,且每个条件后面都跟着一个代码块。if-else 条件选择是一个表达式,并且所有分支都必须返回相同的类型。

fn main() { let n = 5; if n < 0 { print!("{} is negative", n); } else if n > 0 { print!("{} is positive", n); } else { print!("{} is zero", n); } let big_n = if n < 10 && n > -10 { println!(", and is a small number, increase ten-fold"); // 这个表达式返回一个 `i32` 类型。 10 * n } else { println!(", and is a big number, half the number"); // 这个表达式也必须返回一个 `i32` 类型。 n / 2 // 试一试 ^ 试着加上一个分号来结束这条表达式。 }; // ^ 不要忘记在这里加上一个分号!所有的 `let` 绑定都需要它。 println!("{} -> {}", n, big_n); }

if let

在一些场合下,用 match 匹配枚举类型并不优雅。比如:

#![allow(unused)] fn main() { // 将 `optional` 定为 `Option<i32>` 类型 let optional = Some(7); match optional { Some(i) => { println!("This is a really long string and `{:?}`", i); // ^ 行首需要 2 层缩进。这里从 optional 中解构出 `i`。 // 译注:正确的缩进是好的,但并不是 “不缩进就不能运行” 这个意思。 }, _ => {}, // ^ 必须有,因为 `match` 需要覆盖全部情况。不觉得这行很多余吗? }; }

if let 在这样的场合要简洁得多,并且允许指明数种失败情形下的选项:

fn main() { // 全部都是 `Option<i32>` 类型 let number = Some(7); let letter: Option<i32> = None; let emoticon: Option<i32> = None; // `if let` 结构读作:若 `let` 将 `number` 解构成 `Some(i)`,则执行 // 语句块(`{}`) if let Some(i) = number { println!("Matched {:?}!", i); } // 如果要指明失败情形,就使用 else: if let Some(i) = letter { println!("Matched {:?}!", i); } else { // 解构失败。切换到失败情形。 println!("Didn't match a number. Let's go with a letter!"); }; // 提供另一种失败情况下的条件。 let i_like_letters = false; if let Some(i) = emoticon { println!("Matched {:?}!", i); // 解构失败。使用 `else if` 来判断是否满足上面提供的条件。 } else if i_like_letters { println!("Didn't match a number. Let's go with a letter!"); } else { // 条件的值为 false。于是以下是默认的分支: println!("I don't like letters. Let's go with an emoticon :)!"); }; }

同样,可以用 if let 匹配任何枚举值:

// 以这个 enum 类型为例 enum Foo { Bar, Baz, Qux(u32) } fn main() { // 创建变量 let a = Foo::Bar; let b = Foo::Baz; let c = Foo::Qux(100); // 变量 a 匹配到了 Foo::Bar if let Foo::Bar = a { println!("a is foobar"); } // 变量 b 没有匹配到 Foo::Bar,因此什么也不会打印。 if let Foo::Bar = b { println!("b is foobar"); } // 变量 c 匹配到了 Foo::Qux,它带有一个值,就和上面例子中的 Some() 类似。 if let Foo::Qux(value) = c { println!("c is {}", value); } }

另一个好处是:if let 允许匹配枚举非参数化的变量,即枚举未注明 #[derive(PartialEq)],我们也没有为其实现 PartialEq。在这种情况下,通常 if Foo::Bar==a 会出错,因为此类枚举的实例不具有可比性。但是,if let 是可行的。

你想挑战一下吗?使用 if let修复以下示例:

// 该枚举故意未注明 `#[derive(PartialEq)]`, // 并且也没为其实现 `PartialEq`。这就是为什么下面比较 `Foo::Bar==a` 会失败的原因。 enum Foo {Bar} fn main() { let a = Foo::Bar; // 变量匹配 Foo::Bar if Foo::Bar == a { // ^-- 这就是编译时发现的错误。使用 `if let` 来替换它。 println!("a is foobar"); } }