Zig 循环
在 Zig 编程语言中,循环是用于重复执行代码块的基本控制结构。Zig 提供简洁而灵活的循环语法,主要包括 for
循环和 while
循环,设计上避免了复杂性,同时保证类型安全和性能。以下是对 Zig 循环的中文讲解,涵盖 for
和 while
循环的用法、特性、示例代码及注意事项,基于 Zig 0.14.1(截至 2025 年 5 月的稳定版),力求简洁清晰。
1. Zig 循环概述
Zig 的循环结构用于迭代数据(如数组、切片)或根据条件重复执行代码。特点包括:
- 显式语法:无隐藏控制流,易于理解。
- 类型安全:迭代器和条件受编译时检查。
- 性能优化:支持编译时展开(
comptime
),减少运行时开销。 - 无
do-while
:Zig 简化设计,仅提供for
和while
。
2. For 循环
for
循环用于迭代可迭代对象(如数组、切片、范围)。Zig 的 for
循环语法直观,特别适合处理序列数据。
语法
for (items) |item| {
// 循环体
}
items
:可迭代对象(如数组、切片)。item
:每次迭代捕获的元素。- 支持多变量捕获、索引和范围。
基本示例
const std = @import("std");
pub fn main() !void {
const numbers = [_]u8{1, 2, 3, 4, 5};
const stdout = std.io.getStdOut().writer();
for (numbers) |n| {
try stdout.print("数字: {}\n", .{n});
}
}
输出:
数字: 1
数字: 2
数字: 3
数字: 4
数字: 5
说明:
|n|
:捕获数组元素,n
是每次迭代的值。- 数组
[_]u8
自动推断长度。
带索引的 For 循环
使用 |item, index|
捕获元素和索引:
const std = @import("std");
pub fn main() !void {
const letters = [_]u8{'a', 'b', 'c'};
const stdout = std.io.getStdOut().writer();
for (letters, 0..) |letter, i| {
try stdout.print("索引: {}, 字母: {}\n", .{i, letter});
}
}
输出:
索引: 0, 字母: 97
索引: 1, 字母: 98
索引: 2, 字母: 99
说明:
0..
:生成索引范围,自动匹配数组长度。letter
是u8
类型,打印时显示 ASCII 值。
迭代范围
Zig 支持直接迭代数字范围:
for (0..5) |i| {
try std.io.getStdOut().writer().print("计数: {}\n", .{i});
}
输出:
计数: 0
计数: 1
计数: 2
计数: 3
计数: 4
多变量捕获
同时迭代多个序列:
const std = @import("std");
pub fn main() !void {
const a = [_]u8{1, 2, 3};
const b = [_]u8{4, 5, 6};
const stdout = std.io.getStdOut().writer();
for (a, b) |x, y| {
try stdout.print("a: {}, b: {}\n", .{x, y});
}
}
输出:
a: 1, b: 4
a: 2, b: 5
a: 3, b: 6
3. While 循环
while
循环用于基于条件重复执行代码,支持继续表达式和错误处理。
语法
while (条件) : (继续表达式) {
// 循环体
}
条件
:布尔表达式,决定是否继续循环。继续表达式
:可选,每次循环末尾执行(如递增计数器)。
基本示例
const std = @import("std");
pub fn main() !void {
var i: u8 = 0;
const stdout = std.io.getStdOut().writer();
while (i < 3) : (i += 1) {
try stdout.print("计数: {}\n", .{i});
}
}
输出:
计数: 0
计数: 1
计数: 2
说明:
: (i += 1)
:继续表达式,循环末尾执行。- 条件
i < 3
控制循环退出。
While 与可选类型
while
可用于处理可选值(?T
):
const std = @import("std");
pub fn main() !void {
var maybe_num: ?u8 = 10;
const stdout = std.io.getStdOut().writer();
while (maybe_num) |num| {
try stdout.print("值: {}\n", .{num});
maybe_num = null; // 退出循环
}
}
输出:
值: 10
While 与错误处理
while
支持错误联合(!T
):
const std = @import("std");
const MyError = error{Overflow};
fn next_number(n: u8) MyError!u8 {
if (n >= 255) return MyError.Overflow;
return n + 1;
}
pub fn main() !void {
var num: u8 = 0;
const stdout = std.io.getStdOut().writer();
while (true) {
num = next_number(num) catch |err| {
try stdout.print("错误: {}\n", .{err});
break;
};
try stdout.print("数字: {}\n", .{num});
if (num >= 3) break;
}
}
输出:
数字: 1
数字: 2
数字: 3
说明:
catch
:捕获错误,退出循环。break
:显式终止循环。
4. 循环控制
Zig 提供 break
和 continue
控制循环:
break
:退出循环。continue
:跳到下一次迭代。
示例
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
var i: u8 = 0;
while (i < 5) : (i += 1) {
if (i == 2) continue; // 跳过 i == 2
if (i == 4) break; // 在 i == 4 时退出
try stdout.print("i: {}\n", .{i});
}
}
输出:
i: 0
i: 1
i: 3
5. 编译时循环
Zig 支持 comptime
循环,在编译时展开,优化性能。
示例
const std = @import("std");
const sum = comptime blk: {
var total: u32 = 0;
for ([_]u8{1, 2, 3}) |n| {
total += n;
}
break :blk total;
};
pub fn main() !void {
try std.io.getStdOut().writer().print("编译时和: {}\n", .{sum});
}
输出:
编译时和: 6
说明:
comptime
确保循环在编译时执行,结果为常量。- 适合生成静态数据或优化代码。
6. 注意事项
- 类型安全:
- 迭代器类型必须匹配(如数组、切片)。
- 错误联合需用
try
或catch
处理。 - 性能:
for
循环针对数组/切片优化,编译器可展开循环。- 使用
comptime
减少运行时开销。 - 边界检查:
- Zig 默认启用数组边界检查,防止越界:
zig var arr = [_]u8{1, 2}; // arr[2]; // 编译时或运行时错误
- 调试:
- 使用
std.debug.print
检查循环状态。 - 编译时错误提示明确,检查迭代器类型或条件。
- 与 C 互操作:
- 循环常用于处理 C 风格数组(
[*]T
),注意指针安全。
7. 综合示例
以下示例结合 for
和 while
循环,处理数组和错误:
const std = @import("std");
const MyError = error{InvalidValue};
fn validate(n: u8) MyError!u8 {
if (n > 100) return MyError.InvalidValue;
return n;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const numbers = [_]u8{10, 150, 30, 200};
// For 循环:验证数组元素
for (numbers, 0..) |n, i| {
const valid = validate(n) catch |err| {
try stdout.print("索引 {} 错误: {}\n", .{i, err});
continue;
};
try stdout.print("索引 {} 有效值: {}\n", .{i, valid});
}
// While 循环:累加直到条件
var sum: u32 = 0;
var i: usize = 0;
while (i < numbers.len) : (i += 1) {
sum += numbers[i];
if (sum > 200) break;
}
try stdout.print("总和: {}\n", .{sum});
}
运行:
zig run example.zig
输出:
索引 0 有效值: 10
索引 1 错误: InvalidValue
索引 2 有效值: 30
索引 3 错误: InvalidValue
总和: 210
说明:
for
循环迭代数组,处理错误。while
循环累加并在条件满足时退出。
8. 总结
Zig 的循环机制简洁高效:
for
循环:适合迭代数组、切片或范围,支持多变量捕获。while
循环:基于条件执行,支持继续表达式和错误处理。- 编译时循环:使用
comptime
优化性能。
注意类型安全、边界检查和错误处理,结合std.debug.print
调试。Zig 的循环设计适合系统编程,兼顾性能和可读性。
如果你需要更复杂的循环示例(如嵌套循环、并发迭代)或有其他问题,请告诉我!