控制流
rust中有if和match两种控制流
1.条件表达式
1.1 if分支
if 是最基本的条件控制结构,用于根据条件执行不同的代码分支:
- 若只有一个条件,使用
if即可,判断条件写在if后面 - 若有两个条件,可以使用
else分支处理另一个条件 - 若大于两个条件,可以在
if和else直接使用else if处理其他的条件,判断条件写在else if后面
let number = 6;
if number > 5 {
println!("数字大于5");
} else if number < 0 {
println!("数字小于0");
} else {
println!("数字在 0 ~ 5 之间");
}这是最传统的 if 用法,根据条件执行相应的代码块。当条件为真时,执行 if 后的代码块;当条件为假且有 else 分支时,执行 else 后的代码块。
1.2 if表达式化
与其他语言不同,Rust 中的 if 不仅是语句,更是表达式,可以返回值:
let number = 6;
let result = if number % 2 == 0 {
"偶数"
} else {
"奇数"
};
println!("数字 {} 是 {}", number, result);这里的关键概念是:大括号 {} 的最后一个表达式就是该代码块的返回值。注意 "偶数" 和 "奇数" 后面都没有分号,这意味着它们是表达式而不是语句,会作为代码块的返回值。
因此在Rust中没有三元表达式?:,因为if本身作为表达式就可以完成对应的功能。
例如以上代码在C++中可以用?:完成:
String str = number % 2 == 0 ? "偶数" : "奇数";1.3 if表达式的类型要求
由于 if 是表达式,编译器需要在编译时确定其返回的类型,因此所有分支必须返回相同类型:
let condition = true;
// 正确:所有分支返回相同类型
let number = if condition {
5
} else {
6
};
println!("number = {}", number);
// 错误示例(会编译失败):
let mixed = if condition {
5 // 整数类型
} else {
"six" // 字符串类型
};这个限制确保了类型安全,编译器可以在编译时就确定变量的类型,避免运行时的类型错误。
1.4 match分支匹配
match 是 Rust 中更强大的分支控制结构,可以匹配多种模式:
let number = 3;
match number {
1 => println!("一"),
2 => println!("二"),
3 => println!("三"),
_ => println!("其他"),
}match 通过模式匹配来决定执行哪个分支。每个分支由模式和对应的代码组成,用 => 连接。_ 是通配符,匹配所有其他情况,通过将其放置于其他分支之后
它类似于其他语言的switch语句,但是功能性远比switch强大。
match必须覆盖被匹配值的所有可能情况,这被称为"穷尽性"要求:
enum Direction {
North,
South,
East,
West,
}
let dir = Direction::North;
match dir {
Direction::North => "向北前进",
Direction::South => "向南前进",
Direction::East => "向东前进",
Direction::West => "向西前进",
}穷尽性检查是编译时进行的,确保你不会遗漏任何情况。这大大减少了运行时错误的可能性。
match支持多种复杂的模式匹配:
let number = 7;
match number {
1 => println!("一"),
2 | 3 => println!("二或三"), // 多值匹配
4..=6 => println!("四到六"), // 范围匹配
_ => println!("其他"),
}- 多值匹配:使用
|可以匹配多个值 - 范围匹配:使用
..=可以匹配一个范围内的值
模式匹配非常繁杂,功能非常强大,后续会开专门的章节讲解,本博客只是让大家了解存在这样一种分支处理的语法。
关于match,在后面枚举中还会继续介绍
2.循环控制
Rust提供了三种循环表达式,分别是while、loop、for in,用法和其他语言基本类似。
2.1 loop
loop 创建一个无限循环,是最基本的循环结构:
let mut counter = 0;
loop {
counter += 1;
println!("计数: {}", counter);
}loop 会无限执行,是最直接的循环控制方式。当其内部不含任何break,那么整个表达式返回!类型。
2.2 while
while 循环格式如下:
while 条件 {
// 循环体
}在条件为真时持续执行循环体,否则就退出循环。
示例:
let mut number = 5;
while number > 0 {
println!("倒计时: {}", number);
number -= 1;
}
println!("发射!");while 在每次循环开始前检查条件,条件为假时退出循环。这比 loop + if + break 的组合更简洁。
while 循环中也可以使用 break 提前退出,但与 loop 不同的是,while 循环不允许 break 携带返回值:
let mut count = 0;
while count < 10 {
count += 1;
if count == 5 {
break; // 可以 break,但不能 break 值
}
println!("计数: {}", count);
}
let result = while condition { break 42; }; // 错误!while 不能返回值这是因为 while 循环的条件可能一开始就为假,那样循环体根本不会执行,无法确定返回值。
有人可能就有疑问:已经有while了,为什么还需要loop?因为while true 不就可以实现死循环吗?
Rust一切皆表达式,表达式=副作用+返回值,loop与while true 的副作用类似,都是死循环,但是返回值有很大差别。不要用while true循环来代替loop实现死循环,本文后半部分讲到函数会给一个反例。
2.3 for...in...
for 循环用于遍历集合或迭代器,语法如下:
for var in 迭代器 {
}- var为当前迭代对象
- for循环的内容必须是可迭代迭代器,比如数组
示例:
let numbers = [1, 2, 3, 4, 5];
for num in numbers {
println!("数字: {}", num);
}for 循环会自动遍历可迭代对象的每个元素。这是 Rust 中最常用的循环方式,既安全又高效。
in后可以放任何可遍历的迭代器,具体的深入原理会在后续的迭代器章节讲解。在这之前最常见的写法就是:
for var in 数组名 {
}能看懂即可,此处的var就是数组的每一个元素。
同样的,for in也是一个表达式,返回单元类型(),并且break不允许携带返回值==。
2.4 break 和 continue
在循环中,break 用于退出循环,continue 用于跳过本次迭代:
let mut count = 0;
loop {
count += 1;
if count % 2 == 0 {
continue; // 跳过偶数
}
if count > 10 {
break; // 超过10就退出
}
println!("奇数: {}", count);
}continue 会跳过当前循环的剩余代码,直接进入下一次循环。break 会立即退出整个循环。
对于loop来说,break是一种常见的终止循环手段。那么当loop不是死循环,返回的值就不是!了,具体返回的值是什么取决于break。
2.5 break 返回值
loop循环也是表达式,可以通过 break 返回值,在break与分号;之间可以携带一个返回值。
let mut num = 1;
let result = loop {
if num % 2 == 0 {
break num; // 返回 num 的值
}
num += 1;
};
println!("第一个偶数: {}", result);这里 break num 表示退出循环并返回 num 的值。整个 loop 表达式的值就是 break 后面的值。
当break;的时候,也就是break不携带值,此时返回的是一个()单元类型。
只有loop循环可以用break返回值,其他两种循环不可以
2.6 标签跳转
当有嵌套循环时,可以使用标签来指定 break 或 continue 要影响哪个循环,语法如下:
'标签A loop {
'标签B while ... {
if ... {
break '标签A;
} else {
continue `标签A;
}
}
}语法中,'标签A代表外层循环,'标签B代表内层循环,标签必须以单引号开头。在while 循环内部,可以通过break '标签A和continue '标签A 直接控制外层循环。
示例:
'outer: loop {
println!("进入外层循环");
'inner: loop {
println!("进入内层循环");
break 'outer; // 跳出外层循环
}
println!("这行代码不会执行");
}
println!("退出所有循环");这种标签这在复杂的嵌套循环中很有用,可以快速跳出多层循环。
当使用标签跳转时,break 也可以携带返回值,但只能在 loop 循环中使用:
let result = 'outer: loop {
let mut inner_count = 0;
'inner: while inner_count < 5 {
inner_count += 1;
println!("内层计数: {}", inner_count);
if inner_count == 3 {
break 'outer inner_count; // 跳出外层循环并返回值
}
}
println!("这行代码不会执行");
};
println!("返回值: {}", result); // 输出: 返回值: 3此处在 break 'outer的同时,携带了一个返回值inner_count,因为'outer是外层的loop循环,所以允许返回。
标签跳转的返回值只能用于 loop 循环,while 和 for 循环即使使用标签也不能返回值。
要求必须在编译期拿到结果,于是发生冲突就报错了。
