Rust loop 循环
Rust 有三种重复执行代码的方式:loop、while 和 for。这一页讲 loop,它是三者中最简单、最直接的一种——一直重复下去,直到你让它停下来。
基本的 loop
Section titled “基本的 loop”fn main() { let mut count = 0;
loop { count += 1; println!("{count}");
if count == 3 { break; } }}输出:
123loop 本身永远不会停,让它结束的是 break。要是没有那句 if count == 3 { break; },这个程序就会一直打印下去。
从循环返回值
Section titled “从循环返回值”有一件事只有 loop 能做,while 和 for 做不到:你可以在 break 后面写一个值,这个值就成了整个循环的结果:
fn main() { let mut count = 0;
let result = loop { count += 1; if count == 10 { break count * 2; // 停下来,并交回一个值 } };
println!("{result}");}输出:
20像“不断重试直到成功,然后把结果给我”这种场景,用它就很方便——在真实的代码里,你见到这种写法的次数会比想象中多。
注意循环结尾的 } 后面有个分号。整个 loop { ... } 是 let result = ...; 的右边部分,所以这条 let 语句末尾需要 ;,就像 let x = 5; 一样。
为什么用 loop 而不是 while true?
Section titled “为什么用 loop 而不是 while true?”如果你学过别的语言,可能会把无限循环写成 while true { ... }。这在 Rust 里也能运行,但编译器会给出警告:
warning: denote infinite loops with `loop { ... }` --> src/main.rs:5:5 |5 | while true { | ^^^^^^^^^^ help: use `loop`这条警告的意思是:请用 loop { ... } 来表示无限循环。这不只是风格问题。Rust 知道 loop 的循环体一定会执行,而且唯一的出口就是 break。对于 while true,Rust 不会这样假设,因为它不去看条件的值。当一个变量在循环里才被赋值时,这一点就很关键了:
fn main() { let mut n = 1; let answer; // 还没有值
loop { if n * n > 50 { answer = n * n; // 在离开之前给它赋值 break; } n += 1; }
println!("第一个大于 50 的平方数是 {answer}");}输出:
第一个大于 50 的平方数是 64用 loop 时,Rust 能看出走到 println! 的唯一途径就是那个 break,所以 answer 一定已经赋值了。把 loop 改成 while true,你就会得到 error[E0381]: used binding answer is possibly-uninitialized(使用的绑定 answer 可能未初始化)。编译器认为,这个循环有可能一次 if 都没执行就结束了。
实际写代码时,这个程序最简洁的写法是用上面学过的带值的 break:let answer = loop { ... break n * n; ... };。不管哪种写法,道理都一样:当你的意思是“一直循环,直到我 break”,就写 loop。
什么时候用 loop
Section titled “什么时候用 loop”如果你事先不知道要重复多少次——你是在等某个条件成立,而不是数过一个范围或一个列表——那 loop 就是合适的选择。如果是计数或遍历集合,while 和 for(接下来会讲)通常读起来更清楚。
1. 发射倒计时
Section titled “1. 发射倒计时”用 loop 打印从 5 到 1 的倒计时,然后打印 发射!。提示:从 let mut n = 5; 开始,等 n 到 0 时 break。
查看答案
fn main() { let mut n = 5;
loop { if n == 0 { break; } println!("{n}..."); n -= 1; }
println!("发射!");}输出:
5...4...3...2...1...发射!检查写在最前面,所以当 n 变成 0 时,循环在打印 0... 之前就停下了。
2. 第一个大于 1000 的 2 的幂
Section titled “2. 第一个大于 1000 的 2 的幂”从 1 开始不断翻倍。用带值的 break 得到第一个大于 1000 的数,并统计一共翻倍了多少次。提示:在循环外面放一个 mut 计数器,写成 let power = loop { ... };。
查看答案
fn main() { let mut value = 1; let mut doublings = 0;
let power = loop { value *= 2; doublings += 1; if value > 1000 { break value; } };
println!("翻倍 {doublings} 次后得到 {power}");}输出:
翻倍 10 次后得到 1024break value; 结束循环,并把 value 交给 power。计数器放在循环外面,所以循环结束后它的值还在。
loop会一直重复,直到遇到break才停下——一定要确保有一个break。break value;会停止循环,并且把value作为整个循环表达式的结果返回。- 要写
loop,不要写while true:Rust 知道loop的循环体一定会执行,这能帮它检查你的变量。 - 当你要“一直重复,直到某件事发生”时用
loop;要数固定的次数时就不必用它。
小测验
1. 是什么让一个单纯的 loop 不会永远运行下去?
2. 在循环里写 break count * 2; 有什么效果?
3. 根据这一页的内容,什么时候 loop 比 while 或 for 更合适?
4. 在 Rust 里写 while true { ... } 会怎样?
得分: 0 / 4
- 使用循环重复执行——《Rust 程序设计语言》:官方对
loop、while和for的入门介绍。 - 从循环返回值——《Rust 程序设计语言》:专门讲带值
break的一小节。 - loop 循环——《通过例子学 Rust》:
loop、break和continue的可运行示例。 - 从 loop 循环返回——《通过例子学 Rust》:再来一个小例子,看循环怎样交回一个值。
- The
loopkeyword — 标准库文档(英文):简明地说明loop和break如何配合使用。