Day 9: 循环 - While、For与Break/Continue
欢迎来到第九天!循环是编程中用于执行重复任务不可或缺的结构。今天,我们将学习Zig中的两种主要循环:while 和 for。Zig的循环设计在保持与C相似的语法的同时,通过一些独特的改进,使其在遍历数据结构时更安全、更直观。我们还将学习如何使用 break 和 continue 来精确控制循环的执行流程。
2. while 循环
Section titled “2. while 循环”while 循环会在给定条件为 true 时持续执行一个代码块。
-
基本语法:
var i: u32 = 0;while (i < 5) {// ...i += 1;} -
while与else:while循环有一个特殊的else分支,它在循环正常结束(即循环条件变为false)时执行。如果循环是通过break提前退出的,else分支将不会被执行。var j: u32 = 0;while (j < 5) {// ...j += 1;} else {// 这段代码会在 j >= 5 时执行} -
while与可选类型解包:while可以像if一样用于解包可选类型,这在实现迭代器等模式时非常有用。var list = ... // 假设是一个返回 ?Node 的链表while (list.next) |node| {// 只要 list.next 不是 null,就继续循环// node 是解包后的值list = node;}
3. for 循环
Section titled “3. for 循环”Zig的 for 循环专门用于遍历数组、切片或元组的元素,它比C风格的 for (i=0; i<len; i++) 更安全,可以有效防止“差一错误”(off-by-one errors)。
-
遍历元素:
const items = [_]i32{ 10, 20, 30 };for (items) |item|// item 将依次是 10, 20, 30} -
遍历元素和索引: 如果你同时需要元素和它的索引,可以使用
|item, index|的形式。for (items) |item, index| {std.debug.print("items[{d}] = {d}\n", .{ index, item });} -
for也是表达式: 与if和while一样,for也可以有else分支,在循环正常完成(即遍历完所有元素)时执行。如果循环被break中断,else分支不会执行。
4. break 和 continue
Section titled “4. break 和 continue”continue: 立即跳过当前循环的剩余部分,开始下一次迭代。break: 立即终止整个循环。
var i: u32 = 0;while (i < 10) { i += 1; if (i == 3) continue; // 跳过 i=3 的情况 if (i == 8) break; // 当 i=8 时退出循环 // ...}-
带标签的
break和continue: 当存在嵌套循环时,可以使用标签来指定break或continue作用于哪个循环。outer_loop: while (true) {inner_loop: while (true) {// ...break :outer_loop; // 直接跳出外层循环}}
5. 无限循环
Section titled “5. 无限循环”在Zig中,创建一个无限循环的标准方式是 while (true)。这在需要持续运行的服务或事件循环中很常见。由于Zig强大的编译期分析能力,while (true) 是完全安全的,编译器理解其意图。
while (true) { // 等待并处理请求 if (should_shutdown) { break; }}6. 示例:for 求和
Section titled “6. 示例:for 求和”使用 for 循环来计算一个切片中所有元素的和。
const std = @import("std");
fn sum(slice: []const i32) i32 { var total: i32 = 0; for (slice) |value| { total += value; } return total;}
pub fn main() !void { const numbers = [_]i32{ 1, 2, 3, 4, 5 }; const total = sum(&numbers); std.debug.print("Sum: {d}\n", .{total}); // 输出: Sum: 15}7. 实践练习:冒泡排序
Section titled “7. 实践练习:冒泡排序”这是一个经典的算法练习,非常适合用来实践循环和数组操作。
- 创建一个函数
fn bubbleSort(slice: []i32) void。 - 使用嵌套的
for或while循环来实现冒泡排序算法。 - 外层循环控制排序的轮数,内层循环用于比较和交换相邻的元素。
- 在
main函数中创建一个可变数组,调用bubbleSort,然后打印排序后的结果。
提示: 你需要一个 var 数组,因为排序过程需要修改它。
8. 常见问题
Section titled “8. 常见问题”问:Zig有像C那样的 for (;;) 或 for (i=0; ...) 循环吗?
答:没有。Zig的 for 专门用于迭代。C风格的 for 循环可以通过 while 循环轻松模拟,Zig的设计者认为专门的迭代 for 更清晰、更安全。
// C: for (int i = 0; i < 10; i++)// Zig:var i: u32 = 0;while (i < 10) : (i += 1) { // ...}注意 while 条件后面的 :(i += 1),这是一个 continue 表达式,它会在每次循环体执行完毕后执行,完美模拟了C for 循环的第三部分。
问:标签名会与其他变量名冲突吗?
答:不会。标签有自己的命名空间,所以你可以使用与变量相同的名字作为标签,尽管这可能不是一个好的编码风格。例如 const my_loop = 10; my_loop: while ... 是合法的。
今天,我们掌握了Zig中的 while 和 for 循环。我们学习了它们作为表达式的特性(else 分支),for 在遍历集合时的安全性和便利性,以及如何使用 break、continue 和标签来精细控制循环。这些结构是构建复杂逻辑和算法的基础。
明天,我们将进入一个非常重要的话题:函数。我们将学习如何声明函数、传递参数以及处理多返回值。