改变流程控制, if/else for 等。

if-else

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

if-else

  1. fn main() {
  2. let n = 5;
  3. if n < 0 {
  4. print!("{} is negative", n);
  5. } else if n > 0 {
  6. print!("{} is positive", n);
  7. } else {
  8. print!("{} is zero", n);
  9. }
  10. }

let-if

  1. fn main() {
  2. let n = 5;
  3. let big_n =
  4. if n < 10 && n > -10 {
  5. println!(", and is a small number, increase ten-fold");
  6. // 这个表达式返回一个 `i32` 类型。
  7. 10 * n
  8. } else {
  9. println!(", and is a big number, half the number");
  10. // 这个表达式也必须返回一个 `i32` 类型。
  11. n / 2
  12. };
  13. // ^ 不要忘记在这里加上一个分号!所有的 `let` 绑定都需要它。
  14. println!("{} -> {}", n, big_n);
  15. }

loop 循环

使用 loop 来实现无限循环。

  1. fn main() {
  2. let mut count = 0u32;
  3. // 无限循环
  4. loop {
  5. count += 1;
  6. if count == 3 {
  7. println!("three");
  8. // 跳过这次迭代的剩下内容
  9. continue;
  10. }
  11. println!("{}", count);
  12. if count == 5 {
  13. println!("OK, that's enough");
  14. // 退出循环
  15. break;
  16. }
  17. }
  18. }

嵌套循环和标签

在处理嵌套循环的时候可以 breakcontinue 外层循环。在这类情形中,循环必须 用一些 'label(标签)来注明,并且标签必须传递给 break/continue 语句。

  1. #![allow(unreachable_code)]
  2. fn main() {
  3. 'outer: loop {
  4. println!("Entered the outer loop");
  5. 'inner: loop {
  6. println!("Entered the inner loop");
  7. // 这只是中断内部的循环
  8. //break;
  9. // 这会中断外层循环
  10. break 'outer;
  11. }
  12. println!("This point will never be reached");
  13. }
  14. println!("Exited the outer loop");
  15. }

从 loop 循环中返回

若操作返回一个值,将该值放在 break 之后,它就会被 loop 表达式返回。

  1. fn main() {
  2. let mut counter = 0;
  3. let result = loop {
  4. counter += 1;
  5. if counter == 10 {
  6. break counter * 2;
  7. }
  8. };
  9. assert_eq!(result, 20);
  10. }

while 循环

  1. fn main() {
  2. // 计数器变量
  3. let mut n = 1;
  4. // 当 `n` 小于 101 时循环
  5. while n < 101 {
  6. if n % 15 == 0 {
  7. println!("fizzbuzz");
  8. } else if n % 3 == 0 {
  9. println!("fizz");
  10. } else if n % 5 == 0 {
  11. println!("buzz");
  12. } else {
  13. println!("{}", n);
  14. }
  15. // 计数器值加 1
  16. n += 1;
  17. }
  18. }

for 循环

区间

for in 结构可以遍历一个 Iterator(迭代器)。创建迭代器的一个最简单的方法是使用区间标记 a..b。这会生成从 a(包含此值) 到 b(不含此值)的,步长为 1 的 一系列值。

  1. fn main() {
  2. // `n` 将在每次迭代中分别取 1, 2, ..., 100
  3. for n in 1..101 {
  4. println!("{}", n);
  5. }
  6. }

使用a..=b表示两端都包含在内的范围

迭代器

如果没有特别指定,for 循环会对给出的集合应用 into_iter 函数,把它转换成 一个迭代器。其他的方法有 iteriter_mut 函数。

  • iter - 在每次迭代中借用集合中的一个元素。这样集合本身不会被改变,循环之后仍可以使用。 ```rust fn main() { let names = vec![“Bob”, “Frank”, “Ferris”];

    for name in names.iter() {

    1. match name {
    2. &"Ferris" => println!("There is a rustacean among us!"),
    3. _ => println!("Hello {}", name),
    4. }

    } }

  1. - `into_iter` - 会消耗集合。在每次迭代中,集合中的数据本身会被提供。一旦集合被消耗了,之后就无法再使用了,因为它已经在循环中被 “移除”(move)了。
  2. ```rust
  3. for name in names.into_iter() {
  4. match name {
  5. "Ferris" => println!("There is a rustacean among us!"),
  6. _ => println!("Hello {}", name),
  7. }
  8. }
  • iter_mut - 可变地(mutably)借用集合中的每个元素,从而允许集合被就地修改。
    1. for name in names.iter_mut() {
    2. *name = match name {
    3. &mut "Ferris" => "There is a rustacean among us!",
    4. _ => "Hello",
    5. }
    6. }

    match 匹配

    类似于其他语言的 switch
    match 分支必须覆盖所有可能的值。
    1. let number = 13;
    2. match number {
    3. // 匹配单个值
    4. 1 => println!("One!"),
    5. // 匹配多个值
    6. 2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
    7. // 匹配一个闭区间范围
    8. 13..=19 => println!("A teen"),
    9. // 处理其他情况
    10. _ => println!("Ain't special"),
    11. }

    let match

    1. let boolean = true;
    2. // match 也是一个表达式
    3. let binary = match boolean {
    4. // match 分支必须覆盖所有可能的值
    5. false => 0,
    6. true => 1,
    7. // 试一试 ^ 将其中一条分支注释掉
    8. };

    解构

    元组

    ```rust fn main() { let pair = (0, -2); // match 可以解构一个元组 match pair {
    1. // 解构出第二个值
    2. (0, y) => println!("First is `0` and `y` is `{:?}`", y),
    3. (x, 0) => println!("`x` is `{:?}` and last is `0`", x),
    4. _ => println!("It doesn't matter what they are"),
    5. // `_` 表示不将值绑定到变量
    } }
  1. <a name="E4Doa"></a>
  2. #### 枚举
  3. ```rust
  4. // 需要 `allow` 来消除警告,因为只使用了枚举类型的一种取值。
  5. #[allow(dead_code)]
  6. enum Color {
  7. // 这三个取值仅由它们的名字(而非类型)来指定。
  8. Red,
  9. Blue,
  10. Green,
  11. // 这些则把 `u32` 元组赋予不同的名字,以色彩模型命名。
  12. RGB(u32, u32, u32),
  13. }
  14. fn main() {
  15. let color = Color::RGB(122, 17, 40);
  16. println!("What color is it?");
  17. // 可以使用 `match` 来解构 `enum`。
  18. match color {
  19. Color::Red => println!("The color is Red!"),
  20. Color::Blue => println!("The color is Blue!"),
  21. Color::Green => println!("The color is Green!"),
  22. Color::RGB(r, g, b) =>
  23. println!("Red: {}, green: {}, and blue: {}!", r, g, b),
  24. // 不需要其它分支,因为所有的情形都已覆盖
  25. }
  26. }

指针和引用

对指针来说,解构(destructure)和解引用(dereference)要区分开,因为这两者的概念 是不同的。

  • 解引用使用 *
  • 解构使用 &ref、和 ref mut ``rust fn main() { // 获得一个i32类型的引用。&` 表示取引用。 let reference = &4;

    match reference {

    1. // 译注:因此可用 `val` 表示被 `reference` 引用的值 4。
    2. &val => println!("Got a value via destructuring: {:?}", val),

    }

    // 如果不想用 &,需要在匹配前解引用。 match *reference {

    1. val => println!("Got a value via dereferencing: {:?}", val),

    }

    // 如果一开始就不用引用,会怎样? reference 是一个 & 类型,因为赋值语句 // 的右边已经是一个引用。但下面这个不是引用,因为右边不是。 let _not_a_reference = 3;

    // Rust 对这种情况提供了 ref。它更改了赋值行为,从而可以对具体值创建引用。 // 下面这行将得到一个引用。 let ref _is_a_reference = 3;

    // 相应地,定义两个非引用的变量,通过 refref mut 仍可取得其引用。 let value = 5; let mut mut_value = 6;

    // 使用 ref 关键字来创建引用。 // 译注:下面的 r 是 &i32 类型,它像 i32 一样可以直接打印,因此用法上 // 似乎看不出什么区别。但读者可以把 println! 中的 r 改成 *r,仍然能 // 正常运行。前面例子中的 println! 里就不能是 *val,因为不能对整数解 // 引用。 match value {

    1. ref r => println!("Got a reference to a value: {:?}", r),

    }

    // 类似地使用 ref mut。 match mut_value {

    1. ref mut m => {
    2. // 已经获得了 `mut_value` 的引用,先要解引用,才能改变它的值。
    3. *m += 10;
    4. println!("We added 10. `mut_value`: {:?}", m);
    5. },

    } }

  1. <a name="d8MPv"></a>
  2. #### 结构体
  3. ```rust
  4. fn main() {
  5. struct Foo { x: (u32, u32), y: u32 }
  6. // 解构结构体的成员
  7. let foo = Foo { x: (1, 2), y: 3 };
  8. let Foo { x: (a, b), y } = foo;
  9. println!("a = {}, b = {}, y = {} ", a, b, y);
  10. // 可以解构结构体并重命名变量,成员顺序并不重要
  11. let Foo { y: i, x: j } = foo;
  12. println!("i = {:?}, j = {:?}", i, j);
  13. // 也可以忽略某些变量
  14. let Foo { y, .. } = foo;
  15. println!("y = {}", y);
  16. // 这将得到一个错误:模式中没有提及 `x` 字段
  17. // let Foo { y } = foo;
  18. }

守卫

可以加上 match 守卫(guard) 来过滤分支。

  1. fn main() {
  2. let pair = (2, -2);
  3. println!("Tell me about {:?}", pair);
  4. match pair {
  5. (x, y) if x == y => println!("These are twins"),
  6. // ^ `if` 条件部分是一个守卫
  7. (x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
  8. (x, _) if x % 2 == 1 => println!("The first one is odd"),
  9. _ => println!("No correlation..."),
  10. }
  11. }

绑定

match 中间接地访问一个变量,需要重新绑定。需要用到 @ 字符

  1. fn main() {
  2. let age = 11u32;
  3. match age {
  4. 0 => println!("I'm not born yet I guess"),
  5. // 在 1 ... 12 分支中绑定匹配值到 `n` 。现在年龄就可以读取了。
  6. n @ 1 ... 12 => println!("I'm a child of age {:?}", n),
  7. // 不符合上面的范围。返回结果。
  8. n => println!("I'm an old person of age {:?}", n),
  9. }
  10. }

绑定 Option 等:

  1. fn main() {
  2. let age = 11u32;
  3. match age {
  4. 0 => println!("I'm not born yet I guess"),
  5. // 在 1 ... 12 分支中绑定匹配值到 `n` 。现在年龄就可以读取了。
  6. n @ 1 ... 12 => println!("I'm a child of age {:?}", n),
  7. // 不符合上面的范围。返回结果。
  8. n => println!("I'm an old person of age {:?}", n),
  9. }
  10. }

if let

match 匹配枚举不是很优雅:

  1. fn main() {
  2. let optional = Some(7);
  3. match optional {
  4. Some(i) => {
  5. println!("This is a really long string and `{:?}`", i);
  6. },
  7. _ => {},
  8. // ^ 必须有,因为 `match` 需要覆盖全部情况
  9. };
  10. }

使用 if let 后:

  1. fn main() {
  2. let number = Some(7);
  3. let letter: Option<i32> = None;
  4. // `if let` 结构读作:若 `let` 将 `number` 解构成 `Some(i)`,则执行
  5. // 语句块(`{}`)
  6. if let Some(i) = number {
  7. println!("Matched {:?}!", i);
  8. }
  9. // 如果要指明失败情形,就使用 else:
  10. if let Some(i) = letter {
  11. println!("Matched {:?}!", i);
  12. } else {
  13. // 解构失败。切换到失败情形。
  14. println!("Didn't match a number. Let's go with a letter!");
  15. };
  16. }

if let 有可选的 else/ else if 分句。

匹配枚举值

  1. enum Foo {
  2. Bar,
  3. Qux(u32)
  4. }
  5. fn main() {
  6. // 创建变量
  7. let a = Foo::Bar;
  8. let c = Foo::Qux(100);
  9. // 变量 a 匹配到了 Foo::Bar
  10. if let Foo::Bar = a {
  11. println!("a is foobar");
  12. }
  13. // 变量 c 匹配到了 Foo::Qux,它带有一个值,就和上面例子中的 Some() 类似。
  14. if let Foo::Qux(value) = c {
  15. println!("c is {}", value);
  16. }
  17. }

while let

  1. fn main() {
  2. // 将 `optional` 设为 `Option<i32>` 类型
  3. let mut optional = Some(0);
  4. // 这读作:当 `let` 将 `optional` 解构成 `Some(i)` 时,就
  5. // 执行语句块(`{}`)。否则就 `break`。
  6. while let Some(i) = optional {
  7. if i > 9 {
  8. println!("Greater than 9, quit!");
  9. optional = None;
  10. } else {
  11. println!("`i` is `{:?}`. Try again.", i);
  12. optional = Some(i + 1);
  13. }
  14. }
  15. }