控制流

阅读本篇时请确定自己了解过其他语言的控制流,因为本篇只介绍用法而不解释运行顺序。

Rust提供了4种控制流:ifwhileloopfor

与某些语言不同的是,Rust控制流中的条件表达式都不需要用括号()包围(加不加括号都可以编译,建议不加),并且控制流的花括号{}不可省略

ifelse


格式:

1
2
3
4
5
6
7
if condition {
// code
} else if condition {
// code
} else {
// code
}

例:

1
2
3
if 1 + 1 == 2 {
println!("1+1等于2");
}

while循环


格式:

1
2
3
while condition {
// code
}

loop循环和break


格式:

1
2
3
loop {
// ...
}

loop块内的语句会一直执行,如何跳出后文再说。

for循环


格式:

1
2
for varname in iter/range {
}

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn main() {
let arr = [1, 2, 3];

// 使用下标遍历[0, 3)
for i in 0..3 {
// print!()打印不换行
print!("{}", arr[i]);
}

// 直接遍历
for a in arr {
print!("{}", a);
}
}

输出:

1
123123

字面值0..3的类型是区间(Range),0..3代表左闭右开数列:{012},相应的a..=b表示{aa+1、...、b}。有兴趣了解的话可以看看std::ops::RangeRange功能较多,这里就不过多展开了。

continuebreak


continuebreak可以在所有循环语句(whileloopfor)中使用。

continue用于跳过循环,break用于跳出循环。

continue;break;只对当前循环有效,要指定循环可以在循环语句前添加标签(标签名格式为'tagname)和:,然后使用语句continue 'tagname;break 'tagname

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
fn main() {
let mut ct = 0;
'wh: while ct > -1 {
ct += 1;
'fo: for a in 0..2 {
if ct == 2 {
break 'wh;
} else if a == 1 {
continue 'wh;
}
}
}
}

match匹配


match匹配有三种可混合嵌套使用的用法:值匹配、条件匹配、类型匹配,这里先只介绍值匹配和条件匹配。

类型匹配的内容将在初识枚举中介绍。

值匹配

其中,值匹配用法比较类似C/C++中的switch,下面是值匹配示例:

1
2
3
4
5
6
7
8
9
10
11
12
let mut a = 1;
// ⚠️每条匹配语句之间用,分隔
match a {
1 => a += 1,
2 => {
a += 1;
a *= 2;
}// 花括号后,可写可不写
// _是通配符,相当于C/C++中`switch`的`default`;
// 如果a无法匹配其他语句时,就会匹配到该语句
_ => a += 3,
}

因为a == 1所以上面的match会匹配到1并执行a += 1

注意,所有匹配语句之间无关联,例如上面a匹配到1后就只会执行a += 1,而不会执行a += 3{ a+=1; a*=2; }

此外,使用match匹配时必须确保能完全匹配该类型的所有可能(比如匹配对象为i32时,必须确保数据范围内所有可能值都能被匹配到),否则无法编译

因此如果不使用通配符,就必须这么写:

1
2
3
4
5
6
7
8
let mut a = 1;
match a {
i32::MIN => {}
i32::MIN+1 => {}
...中间略
i32::MAX-1 => {}
i32::MAX => {}
}

match语句允许存在重复的匹配语句,进行match匹配时,match会从上到下判断是否匹配,如果匹配到语句后,下面的语句将不再进行匹配判断,例子:

1
2
3
4
5
match 1 {
1 => println!("匹配到了第一个语句"),
1 => println!("匹配到了第二个语句"),
_ => println!("匹配到了第三个语句"),
}

输出:

1
匹配到了第一个语句

使用Range进行值匹配

上文中,我提到一个区间类型(std::ops::Range),Rust中可以使用Range进行值匹配:

1
2
3
4
5
6
match 1 {
-123..123 => println!("匹配到了第一个语句"),
// 同样的,这一语句不会执行
0..1234 => println!("匹配到了第二个语句"),
_ => {}
}

输出:

1
匹配到了第一个语句

绑定语法

TODO

条件匹配

如果需要更为精细的匹配,可以使用guard语句(卫语句,其实就是match+if):

1
2
3
4
5
6
match 1 {
n if n !=0 => {}
0 => {}
// 需要注意的是,编译器无法判断卫语句的匹配范围,因此这里需要补充一个通配符匹配
_ => {}
}