Ziglings 笔记 62: 循环也是表达式
循环的返回值
在 Ziglings 的第 62 个练习中,我们解锁了循环的新玩法。
在此之前,for 和 while 只是用来重复执行代码的。但就像 if/else 可以作为表达式一样,Zig 的循环也可以有返回值。
挑战:查找并赋值
我们需要在编程语言列表 langs 中寻找第一个名字长度为 3 的语言(即 “Zig”)。
- 如果找到了,把它赋值给
current_lang。 - 如果找遍了整个数组都没找到,把
null赋值给current_lang。
重要的是,我们要把 current_lang 声明为 const,这意味着我们不能使用“先声明 var 再在循环里赋值”的老办法。
解决方案
我们需要利用 for 循环的 else 分支:
const print = @import("std").debug.print;
pub fn main() void {
const langs: [6][]const u8 = .{
"Erlang", "Algol", "C", "OCaml", "Zig", "Prolog",
};
// 核心代码:循环表达式
// 这里的 for 循环整体就是一个表达式,它的结果被赋给了 current_lang
const current_lang: ?[]const u8 = for (langs) |lang| {
// 情况 1: 找到了
// 使用 break 携带一个值跳出循环,这个值就是循环的返回值
if (lang.len == 3) break lang;
} else null; // 情况 2: 没找到 (循环自然结束)
// 必须提供 else 分支作为默认返回值
if (current_lang) |cl| {
print("Current language: {s}\n", .{cl});
} else {
print("Did not find a three-letter language name. :-(\n", .{});
}
}
核心知识点总结
1. break 带值
我们习惯了 break 只是单纯地跳出循环。但在 Zig 中,break 后面可以跟一个表达式,就像函数里的 return 一样。
2. 循环的 else
很多人看到循环后面跟个 else 会觉得奇怪(Python 也有这个特性,但很少用)。
在 Zig 中,当循环作为表达式时,else 是必须的。它处理的是“循环跑完了但没触发 break”的情况。
break返回一种可能的值。else返回另一种可能的值(通常是默认值或 null)。 这两个值的类型必须是兼容的。
3. 为什么要这样设计?
为了不可变性 (Immutability)。
这种写法允许我们将 current_lang 定义为 const。不可变的变量更容易推理,也更不容易出 Bug。这消除了传统写法中 var found = null; ... found = x; 的状态变更过程。
后续预告:我们已经掌握了基本的控制流和数据类型。在进入更高级的编译期编程之前,我们还需要填补一些基础知识的拼图。比如,如何给代码块命名并在嵌套循环中跳转?下一篇我们将学习 Labeled Blocks。