news 2026/9/10 14:47:06

comprehensive-rust 控制流精讲:深入理解 Rust 的 `loop` 无限循环

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
comprehensive-rust 控制流精讲:深入理解 Rust 的 `loop` 无限循环

comprehensive-rust 控制流精讲:深入理解 Rust 的loop无限循环

【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust

loop是 Rust 中最直白的循环关键字:它无条件地无限重复循环体,直到遇到break显式退出。在 Google Android 团队维护的 Rust 课程仓库 comprehensive-rust 中,它是控制流三兄弟(whileloopfor)里唯一"永不自行终止"的构造,也是唯一能带返回值离开的循环。读完本文,你将掌握loop的完整语法、break/continue与标签的配合方式,以及它在服务器常驻、嵌入式 panic 处理、异步状态机等真实场景中的典型用法。

loop的基本形态:永远重复,直到break

课程的 loop.md 开门见山:loop语句只是永远循环,直到出现break。它不需要任何条件表达式,loop { ... }本身即完整语句。

课程给出的示例通过计数器演示了最基础用法:

fn main() { let mut i = 0; loop { i += 1; dbg!(i); if i > 100 { break; } } }

逐行拆解这段代码,可以提炼出loop的核心要素:

  • 循环体没有任何前置条件:与while不同,loop在进入循环体之前不会检查任何布尔表达式,天然是"先做再说"的语义。
  • 计数器需要mut:变量i声明为let mut i = 0;,因为在循环体内执行i += 1会修改它。Rust 默认不可变的规则同样作用于循环计数器。
  • 退出依赖breakif i > 100 { break; }是唯一的出口。若删除这行,程序将无限打印递增的i,永不结束。
  • dbg!用于调试观察dbg!(i)是标准库调试宏,会向 stderr 打印表达式及其值并原样返回该值。课程在 macros.md 中专门介绍过它,适合在讲课或调试时观察循环进度。

整个控制流专题在 loops.md 中明确定位了三种循环关键字的分工:while在条件为真时反复执行,for遍历范围或集合,而loop则用于"没有条件、纯粹靠break决定何时离开"的场景。

loopwhile true的关系

课程<details>折叠块给出了一个重要等价关系:loop的工作方式就像一个while true循环。也就是说,下面两种写法行为一致:

// 写法一:loop loop { // 处理请求... break; // 必须显式退出 } // 写法二:while true(不推荐,Rust 编译器会建议改用 loop) let mut cond = true; while cond { // 处理请求... cond = false; // 或直接 break }

两者都要求循环体内有退出路径,否则就是死循环。但 Rust 社区和本课程都更推荐loop,原因有二:

  1. 意图更清晰loop明确表达"这个循环要一直跑,退出条件在循环体内部决定",而while true仍然暗示存在"条件检查"这一环节。
  2. 配合表达式返回值loop是 Rust 中唯一能保证"只在break处返回"的循环构造,因此它可以作为一个表达式产出值(详见下文),而while做不到这一点。

课程给出的经典应用场景是服务器:一个常驻进程用loop不断接受连接、处理请求,理论上永不退出,只有在收到关闭信号时才break。这类代码在并发专题(如 async.md 的聊天服务器、threads.md 的线程示例)中反复出现。

breakcontinue:控制循环节奏

要驾驭loop,必须掌握breakcontinue这对控制关键字。break-continue.md 给出了一个同时使用两者的完整示例:

fn main() { let mut i = 0; loop { i += 1; if i > 5 { break; } if i % 2 == 0 { continue; } dbg!(i); } }

执行流程分析:

  • continue:立即开始下一次迭代。当i为偶数时,continue跳过后面的dbg!(i),直接进入下一轮i += 1
  • break:完全退出循环。当i超过 5 时,循环终止。
  • 最终输出:i = 1i = 3i = 5(偶数被continue跳过,i = 6时因i > 5直接break)。

这段代码展示了二者的分工:continue处理"本次迭代该跳过的情况",break处理"整个循环该结束的情况"。

loop是唯一能返回值的循环

break-continue.md<details>部分强调了一个语言层面的关键差异:loop是唯一可以返回非平凡(non-trivial)值的循环构造

原因在于类型系统:loop保证只在break语句处返回,所以break可以携带一个表达式,作为整个loop表达式的求值结果;而whilefor还可能在"条件失败"时自然退出,此时无值可返回,因此它们不能产生有意义的值。

fn main() { let mut n = 0; let result = loop { n += 1; if n >= 10 { break n * 2; // break 携带值,作为 loop 的结果 } }; println!("result = {result}"); // 输出 20 }

注意break n * 2后面是分号,它终止循环的同时把n * 2作为loop表达式的值赋给result。这种写法常用于"反复尝试直到满足条件,并把最终值拿出来"的场景,例如重试逻辑、读取用户输入直到合法等。

嵌套循环与标签:精确跳出外层

当循环嵌套时,普通的break只能退出最内层循环。要一次跳出多层,需要用标签(label)。labels.md 展示了这一机制:

fn main() { let s = [[5, 6, 7], [8, 9, 10], [21, 15, 32]]; let mut elements_searched = 0; let target_value = 10; 'outer: for i in 0..=2 { for j in 0..=2 { elements_searched += 1; if s[i][j] == target_value { break 'outer; // 直接跳出外层循环 } } } dbg!(elements_searched); }

要点:

  • 标签写法是'outer:,放在循环关键字之前。
  • break 'outer;从两层循环中一次性跳出,elements_searched最终值为 6([5,6,7,8,9,10]共 6 个元素被检查)。
  • continue同样可以携带标签,用于"跳过外层循环的当前迭代"。

更进一步,课程指出标签break也能作用于任意代码块,而不只是循环:

fn main() { 'label: { break 'label; println!("This line gets skipped"); } println!("after block"); }

break 'label;会直接离开被标记的{}块,块内println!永远不会执行,程序输出after block。这一特性在需要"从嵌套逻辑中提前整体退出"时非常实用。

真实场景一:嵌入式裸机中的loop {}

loop最常见的实战形态之一是"程序结束后的停驻点"。在课程的裸机(bare metal)章节中,main_minimal.rs 的 panic 处理函数这样写:

#[panic_handler] fn panic(info: &PanicInfo) -> ! { error!("{}", info); system_off::<Hvc>().unwrap(); loop {} // 永不返回,处理器在此停驻 }

这里的loop {}是空的无限循环,没有任何break。它在无操作系统的no_std环境中扮演"系统停机"的角色:panic 后处理器没有可退出的地方,loop {}保证程序在错误后不会执行未定义行为,而是稳定地停住。这也是loop类型为!(永不返回类型)的直接体现,正因如此loop {}可以作为-> !函数的末尾表达式。

类似的模式在异步与并发代码中同样常见,例如事件循环、任务轮询的主干。

真实场景二:异步状态机中的loop + match

在 state-machine.md 中,课程展示了 Rust 如何把async fn编译成一个内部状态机,而其poll方法的主干正是loop

impl Future for TwoD10 { type Output = u32; fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> { loop { match *self { TwoD10::Init { modifier } => { /* 发起第一次掷骰 */ } TwoD10::FirstRoll { modifier, fut } => { /* 等待第一次结果 */ } TwoD10::SecondRoll { modifier, first_roll, fut } => { return Poll::Ready(first_roll + second_roll + modifier); } } } } }

loop包裹match是 Rust 中非常经典的习惯用法(loop-match 模式):每一轮迭代根据当前状态推进一"步",状态不满足条件就继续循环,直到达到终态后用returnbreak带值离开。这展示了loop不仅仅用于"服务器永远跑",也用于"反复推进直到完成"的算法式循环。

forwhile的分工:何时该用loop

回到 loops.md 的框架,三种循环的选用建议可以总结为:

循环语义适用场景能否返回值
while条件为真时执行有明确前置/运行时条件否(非平凡值)
loop无条件重复,靠break退出常驻服务、重试、状态机、panic 停驻是(仅loop
for遍历范围或集合迭代元素,配合迭代器否(非平凡值)

其中for底层依赖迭代器(iterator)机制,课程在 for.md 中说明,并在后续专门的迭代器章节(iterators.md)深入展开。若你的循环有一个"范围"可遍历,首选for;若有一个条件可判断,首选while;若循环必须"无条件先跑起来、靠内部逻辑决定何时退出或携带什么值退出",那就该用loop

配套练习:Collatz 序列

为了巩固控制流知识,课程在 exercise.md 安排了 Collatz 序列长度计算练习:对任意正整数 n,若为偶数则 n = n/2,若为奇数则 n = 3n + 1,直到 n 为 1,统计序列长度。其官方解答(见 exercise.rs 与 solution.md)使用while n > 1实现:

/// Determine the length of the collatz sequence beginning at `n`. fn collatz_length(mut n: i32) -> u32 { let mut len = 1; while n > 1 { n = if n % 2 == 0 { n / 2 } else { 3 * n + 1 }; len += 1; } len } fn main() { println!("Length: {}", collatz_length(11)); // should be 15 }

这个练习与本文主题直接相关:如果改用loop实现,写法是loop { ... if n <= 1 { break len; } ... }——这正是"用break携带返回值退出loop"的实战演练。解答中同时体现了mut参数、if作为表达式、隐式返回三个 Rust 特性。课程还提醒:该函数对n <= 0的输入可能陷入死循环或溢出(i32在 n 增长过大时溢出),这正是loop陷阱的绝佳教学素材——无限循环能力越强,越要确保存在可靠的退出条件。

小结

  • loop无条件无限循环,退出完全依赖break,等价于while true,但语义更清晰、能力更强。
  • break可携带表达式,使loop成为唯一能返回非平凡值的循环;continue用于跳过本次迭代。
  • 嵌套循环可用'label标签配合break 'label/continue 'label精确控制跳出层次,标签也可用于普通代码块。
  • 实战形态包括:服务器常驻循环、loop {}停机停驻(main_minimal.rs)、异步状态机的loop + match推进模式。
  • 相关课程材料可在 loops.md、break-continue.md、labels.md、exercise.md 中继续深入,所有示例均可在课程仓库内直接阅读与运行。

【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 14:43:06

毕业季论文降重工具测评与实战技巧

1. 毕业季论文降重实战指南又到一年毕业季&#xff0c;论文查重成了让无数学生头疼的问题。最近我帮学弟学妹们测试了市面上主流的AI降重工具&#xff0c;发现一个惊人的事实&#xff1a;直接用AI生成的论文查重率普遍在90%以上&#xff0c;而经过专业工具处理后的论文可以降到…

作者头像 李华
网站建设 2026/9/10 14:39:53

三维可视化拖拽工具:数字孪生的零代码革命

1. 项目概述&#xff1a;三维可视化的"拖拽革命"去年我在给某制造企业做数字孪生项目时&#xff0c;客户突然提出要调整生产线布局。按照传统开发流程&#xff0c;这需要前端重写Three.js场景代码、后端更新数据接口&#xff0c;至少耗费3人日。但当我打开新版的拖拽…

作者头像 李华