Rust 流程控制
条件选择
if 条件选择是一个表达式(可以用来赋值),并且所有分支都必须返回相同的类型。
判断条件不必用小括号括起来,条件后跟的代码块必须用大括号括起来。
示例一:if 表达式
1fn main() {
2 let number = 3;
3
4 if number != 0 {
5 println!("number was something other than zero");
6 }
7}
示例二:if-else 表达式
1fn main() {
2 let number = 3;
3
4 if number < 5 {
5 println!("condition was true");
6 } else {
7 println!("condition was false");
8 }
9}
示例三:if-else-if 表达式
1fn main() {
2 let n = 5;
3
4 if n < 0 {
5 println!("{} is negative", n);
6 } else if n > 0 {
7 println!("{} is positive", n);
8 } else {
9 println!("{} is zero", n);
10 }
11}
循环语句
Rust 提供了三种循环:loop
、while
和 for
。
loop 循环
无限循环,一般配合break
表达式使用。
示例:
1fn main() {
2 // 这是一个无限循环
3 loop {
4 println!("again!");
5 }
6
7 let mut counter = 0;
8
9 let result = loop {
10 counter += 1;
11 // 设置循环终止条件,并返回一个结果
12 if counter == 10 {
13 break counter * 2;
14 }
15 };
16
17 println!("The result is {}", result);
18}
while 循环
示例:
1fn main() {
2 let mut number = 3;
3
4 while number != 0 {
5 println!("{}!", number);、
6 number = number - 1;
7 }
8
9 println!("LIFTOFF!!!");
10}
for 循环
示例:
1fn main() {
2 // `n` 的值为: 1, 2, ..., 100(`1..101` 等价于 `1..=100`)
3 for n in 1..101 {
4 if n % 15 == 0 {
5 println!("fizzbuzz");
6 } else if n % 3 == 0 {
7 println!("fizz");
8 } else if n % 5 == 0 {
9 println!("buzz");
10 } else {
11 println!("{}", n);
12 }
13 }
14
15 let a = [10, 20, 30, 40, 50];
16 // 使用 for 循环遍历集合中的元素
17 for element in a.iter() {
18 println!("the value is: {}", element);
19 }
20}
模式匹配
Rust 通过 match
关键字提供了模式匹配功能,类似于 C 中的 switch
,但功能更强大。
match
表达式由 match
关键字、用于匹配的值和一个或多个分支构成,每个分支包含一个模式(pattern)以及一个待执行的表达式。
1match VALUE {
2 PATTERN1 => EXPRESSION1,
3 PATTERN2 => EXPRESSION2,
4 PATTERN3 => EXPRESSION3,
5 ...
6 PATTERNn => EXPRESSIONn,
7}
执行过程:依次将 PATTERN1
,PATTERN2
... 和 VALUE
进行比对,一旦匹配成功就执行该分支中 =>
后面的表达式,并且不再继续匹配后面的分支。其中,PATTERNn
可以是字面量、元组、枚举、结构体、通配符、函数等。
模式匹配的要求:
- 所有分支必须穷举所有的可能。
- 每个分支必须是一个表达式,且通常这些表达式的返回值类型必须相同。
示例:
1enum Direction {
2 East,
3 West,
4 North,
5 South,
6}
7fn main() {
8 let d_west = Direction::West;
9 let d_str = match d_west {
10 Direction::East => "East",
11 Direction::North | Direction::South => {
12 panic!("South or North");
13 }, // 该分支一定会触发 panic,返回值类型可以与其他分支不同
14 _ => "West",
15 };
16 println!("{}", d_str);
17}
解构
当待匹配的模式是复合类型时,可以提取复合类型值中的部分数据。
示例一:解构元组
1fn main() {
2 let triple = (0, -2, 3);
3
4 println!("Tell me about {:?}", triple);
5
6 match triple {
7 // 解构元组中第2和第3个元素
8 (0, y, z) => println!("First is `0`, `y` is {:?}, and `z` is {:?}", y, z),
9 // 使用 `..` 忽略其他元素,仅匹配第1个元素
10 (1, ..) => println!("First is `1` and the rest doesn't matter"),
11 // `_` 匹配所有值,通常将它放在最后,用来匹配剩余的所有可能值
12 _ => println!("It doesn't matter what they are"),
13 }
14}
示例二:解构枚举
1#[allow(dead_code)]
2enum Color {
3 Red,
4 Blue,
5 Green,
6 RGB(u32, u32, u32),
7 HSV(u32, u32, u32),
8 HSL(u32, u32, u32),
9 CMY(u32, u32, u32),
10 CMYK(u32, u32, u32, u32),
11}
12
13fn main() {
14 let color = Color::RGB(122, 17, 40);
15
16 println!("What color is it?");
17
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 Color::HSV(h, s, v) =>
25 println!("Hue: {}, saturation: {}, value: {}!", h, s, v),
26 Color::HSL(h, s, l) =>
27 println!("Hue: {}, saturation: {}, lightness: {}!", h, s, l),
28 Color::CMY(c, m, y) =>
29 println!("Cyan: {}, magenta: {}, yellow: {}!", c, m, y),
30 Color::CMYK(c, m, y, k) =>
31 println!("Cyan: {}, magenta: {}, yellow: {}, key (black): {}!", c, m, y, k),
32 }
33}
示例三:解构结构体
1fn main() {
2 struct Foo {
3 x: (u32, u32),
4 y: u32,
5 }
6
7 let foo = Foo { x: (1, 2), y: 3 };
8
9 match foo {
10 Foo { x: (1, b), y } => println!("First of x is 1, b = {}, y = {} ", b, y),
11
12 // 可以对字段(field)重命名
13 Foo { y: 2, x: i } => println!("y is 2, i = {:?}", i),
14 // Foo { y: 2, x } => println!("y is 2, i = {:?}", x),
15
16 // 可以使用 `..` 忽略一些字段(field)
17 Foo { y, .. } => println!("y = {}, we don't care about x", y),
18 }
19}
示例四:匹配范围
1fn main() {
2 let x = 1;
3 match x {
4 1 ..=10 => println!("一到十"),
5 _ => println!("其它"),
6 }
7
8 let c = 'w';
9 match c {
10 'a' ..='z' => println!("小写字母"),
11 'A' ..='Z' => println!("大写字母"),
12 _ => println!("其他字符"),
13 }
14}
示例五:多重匹配
1fn main() {
2 let x = 1;
3 // 匹配多个模式时,使用 `|` 分隔
4 match x {
5 1 | 2 => println!("一或二"),
6 _ => println!("其他"),
7 }
8}
后置条件
一个 if
表达式可以被放在 match
的模式之后,被称为 match guard
。
示例:
1fn main() {
2 let x = 4;
3 let y = false;
4 match x {
5 4 | 5 if y => println!("yes"),
6 _ => println!("no"),
7 }
8}
绑定
可以使用 @
符号将模式中匹配的值绑定一个名称,详细说明见Identifier patterns。
示例:
1fn age() -> u32 {
2 15
3}
4
5fn main() {
6 println!("Tell me what type of person you are");
7
8 match age() {
9 0 => println!("I haven't celebrated my first birthday yet"),
10 n @ 1 ..= 12 => println!("I'm a child of age {:?}", n),
11 n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
12 // Nothing bound. Return the result.
13 n => println!("I'm an old person of age {:?}", n),
14 }
15}
if let
在某些情况下,可以使用 if let
对模式匹配进行简化。
示例:
1fn main() {
2 let number = Some(7);
3 let letter: Option<i32> = None;
4
5 match number {
6 Some(i) => {
7 println!("Matched {:?}!", i);
8 }
9 _ => {} // 此分支什么都不做,但是不能省略,因为模式匹配要列举所有可能
10 };
11
12 // 可以将上面的模式匹配该为下面这种形式
13 if let Some(i) = number {
14 println!("Matched {:?}!", i);
15 }
16
17 // 如果需要对未匹配的情况进行处理,还可以添加 `else` 分支
18 if let Some(i) = letter {
19 println!("Matched {:?}!", i);
20 } else {
21 println!("Didn't match a number. Let's go with a letter!");
22 }
23}
while let
与 if let
类似,使用 while let
也可以对模式匹配进行简化,只关注要匹配的值,其它的值不用做显式处理。
示例:
1fn main() {
2 let mut optional = Some(0);
3
4 loop {
5 match optional {
6 Some(i) => {
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 _ => {
16 break;
17 }
18 }
19 }
20
21 // 上面loop中的模式匹配可以改为下面这种形式
22 while let Some(i) = optional {
23 if i > 9 {
24 println!("Greater than 9, quit!");
25 optional = None; // 这是循环结束条件
26 } else {
27 println!("`i` is `{:?}`. Try again.", i);
28 optional = Some(i + 1);
29 }
30 }
31}