Zig 循环
循环是编程中的基本控制结构,本章将详细介绍 Zig 中的各种循环语句。
while 循环
基本 while 循环
while 循环在条件为真时重复执行代码块:
rust
const std = @import("std");
pub fn main() void {
var i: i32 = 0;
std.debug.print("基本 while 循环:\n", .{});
while (i < 5) {
std.debug.print("i = {}\n", .{i});
i += 1;
}
}带继续表达式的 while 循环
Zig 的 while 循环可以包含一个继续表达式,在每次迭代结束时执行:
rust
const std = @import("std");
pub fn main() void {
var i: i32 = 0;
std.debug.print("带继续表达式的 while 循环:\n", .{});
while (i < 5) : (i += 1) {
std.debug.print("i = {}\n", .{i});
}
}while 循环的可选值处理
while 循环可以处理可选值,当值为 null 时结束循环:
zig
const std = @import("std");
fn getNextNumber(current: i32) ?i32 {
if (current >= 5) return null;
return current + 1;
}
pub fn main() void {
var maybe_number: ?i32 = 0;
std.debug.print("处理可选值的 while 循环:\n", .{});
while (maybe_number) |number| {
std.debug.print("数字: {}\n", .{number});
maybe_number = getNextNumber(number);
}
}while 循环的错误处理
while 循环也可以处理错误联合类型:
rust
const std = @import("std");
const NumberError = error{
TooLarge,
};
fn getNextSafeNumber(current: i32) NumberError!?i32 {
if (current >= 10) return NumberError.TooLarge;
if (current >= 5) return null;
return current + 1;
}
pub fn main() void {
var maybe_number: NumberError!?i32 = 0;
std.debug.print("错误处理的 while 循环:\n", .{});
while (maybe_number) |maybe_num| {
if (maybe_num) |number| {
std.debug.print("安全数字: {}\n", .{number});
maybe_number = getNextSafeNumber(number);
} else {
break;
}
} else |err| {
std.debug.print("遇到错误: {}\n", .{err});
}
}for 循环
遍历数组
for 循环主要用于遍历数组、切片等可迭代对象:
zig
const std = @import("std");
pub fn main() void {
const numbers = [_]i32{ 1, 2, 3, 4, 5 };
std.debug.print("遍历数组:\n", .{});
for (numbers) |number| {
std.debug.print("数字: {}\n", .{number});
}
}遍历切片
rust
const std = @import("std");
pub fn main() void {
const fruits = [_][]const u8{ "苹果", "香蕉", "橙子", "葡萄" };
const slice = fruits[1..3]; // 香蕉, 橙子
std.debug.print("遍历切片:\n", .{});
for (slice) |fruit| {
std.debug.print("水果: {s}\n", .{fruit});
}
}带索引的 for 循环
可以同时获取索引和值:
zig
const std = @import("std");
pub fn main() void {
const colors = [_][]const u8{ "红色", "绿色", "蓝色" };
std.debug.print("带索引的 for 循环:\n", .{});
for (colors, 0..) |color, index| {
std.debug.print("索引 {}: {s}\n", .{ index, color });
}
}遍历字符串
zig
const std = @import("std");
pub fn main() void {
const text = "Hello";
std.debug.print("遍历字符串:\n", .{});
for (text) |char| {
std.debug.print("字符: {c} (ASCII: {})\n", .{ char, char });
}
}范围循环
可以使用范围语法创建循环:
zig
const std = @import("std");
pub fn main() void {
std.debug.print("范围循环 (0 到 4):\n", .{});
for (0..5) |i| {
std.debug.print("i = {}\n", .{i});
}
std.debug.print("范围循环 (2 到 6):\n", .{});
for (2..7) |i| {
std.debug.print("i = {}\n", .{i});
}
}循环控制语句
break 语句
break 用于提前退出循环:
zig
const std = @import("std");
pub fn main() void {
var i: i32 = 0;
std.debug.print("使用 break 的循环:\n", .{});
while (true) {
if (i >= 3) break;
std.debug.print("i = {}\n", .{i});
i += 1;
}
std.debug.print("在 for 循环中使用 break:\n", .{});
for (0..10) |j| {
if (j == 5) break;
std.debug.print("j = {}\n", .{j});
}
}continue 语句
continue 用于跳过当前迭代,继续下一次迭代:
zig
const std = @import("std");
pub fn main() void {
std.debug.print("使用 continue 跳过偶数:\n", .{});
for (0..10) |i| {
if (i % 2 == 0) continue;
std.debug.print("奇数: {}\n", .{i});
}
var j: i32 = 0;
std.debug.print("在 while 循环中使用 continue:\n", .{});
while (j < 10) : (j += 1) {
if (j % 3 == 0) continue;
std.debug.print("不能被3整除: {}\n", .{j});
}
}嵌套循环
基本嵌套循环
zig
const std = @import("std");
pub fn main() void {
std.debug.print("乘法表 (部分):\n", .{});
for (1..4) |i| {
for (1..4) |j| {
const product = i * j;
std.debug.print("{} × {} = {}\t", .{ i, j, product });
}
std.debug.print("\n", .{});
}
}带标签的循环控制
可以使用标签来控制特定的循环:
zig
const std = @import("std");
pub fn main() void {
std.debug.print("带标签的嵌套循环:\n", .{});
outer: for (0..3) |i| {
for (0..3) |j| {
if (i == 1 and j == 1) {
std.debug.print("在 ({}, {}) 处跳出外层循环\n", .{ i, j });
break :outer;
}
std.debug.print("({}, {})\n", .{ i, j });
}
}
std.debug.print("外层循环结束\n", .{});
}标签 continue
zig
const std = @import("std");
pub fn main() void {
std.debug.print("带标签的 continue:\n", .{});
outer: for (0..3) |i| {
for (0..3) |j| {
if (j == 1) {
std.debug.print("跳过外层循环的剩余部分 (i={})\n", .{i});
continue :outer;
}
std.debug.print("({}, {})\n", .{ i, j });
}
}
}循环表达式
while 表达式
while 循环可以作为表达式使用,返回值:
zig
const std = @import("std");
pub fn main() void {
var i: i32 = 0;
const result = while (i < 5) : (i += 1) {
if (i == 3) break i * 10;
} else 0;
std.debug.print("while 表达式结果: {}\n", .{result});
}for 表达式
for 循环也可以作为表达式:
zig
const std = @import("std");
pub fn main() void {
const numbers = [_]i32{ 1, 2, 3, 4, 5 };
const found = for (numbers) |number| {
if (number == 3) break true;
} else false;
std.debug.print("找到数字 3: {}\n", .{found});
const sum = for (numbers) |number| {
// for 循环不能直接累加,这里演示语法
if (number > 10) break number;
} else 0;
std.debug.print("大于 10 的第一个数字: {}\n", .{sum});
}无限循环
使用 while(true)
zig
const std = @import("std");
pub fn main() void {
var counter: i32 = 0;
std.debug.print("无限循环 (会在计数到 3 时退出):\n", .{});
while (true) {
std.debug.print("计数: {}\n", .{counter});
counter += 1;
if (counter >= 3) break;
}
}循环优化
编译时循环
使用 comptime 可以在编译时执行循环:
zig
const std = @import("std");
pub fn main() void {
// 编译时计算
comptime var sum: i32 = 0;
comptime var i: i32 = 1;
comptime {
while (i <= 10) : (i += 1) {
sum += i;
}
}
std.debug.print("1到10的和 (编译时计算): {}\n", .{sum});
// 编译时生成数组
const squares = comptime blk: {
var result: [5]i32 = undefined;
for (result, 0..) |*item, index| {
item.* = @intCast((index + 1) * (index + 1));
}
break :blk result;
};
std.debug.print("前5个平方数: ");
for (squares) |square| {
std.debug.print("{} ", .{square});
}
std.debug.print("\n");
}循环展开
对于小的固定次数循环,编译器可能会自动展开:
zig
const std = @import("std");
pub fn main() void {
const data = [_]i32{ 1, 2, 3, 4, 5 };
var sum: i32 = 0;
// 小循环可能被编译器展开
for (data) |value| {
sum += value;
}
std.debug.print("数组和: {}\n", .{sum});
}实际应用示例
查找算法
zig
const std = @import("std");
fn findElement(array: []const i32, target: i32) ?usize {
for (array, 0..) |element, index| {
if (element == target) {
return index;
}
}
return null;
}
pub fn main() void {
const numbers = [_]i32{ 10, 20, 30, 40, 50 };
const target = 30;
if (findElement(&numbers, target)) |index| {
std.debug.print("找到 {} 在索引 {}\n", .{ target, index });
} else {
std.debug.print("未找到 {}\n", .{target});
}
}数组处理
zig
const std = @import("std");
fn processArray(array: []i32) void {
// 将所有偶数乘以2
for (array) |*element| {
if (element.* % 2 == 0) {
element.* *= 2;
}
}
}
pub fn main() void {
var numbers = [_]i32{ 1, 2, 3, 4, 5, 6 };
std.debug.print("处理前: ");
for (numbers) |num| {
std.debug.print("{} ", .{num});
}
std.debug.print("\n");
processArray(&numbers);
std.debug.print("处理后: ");
for (numbers) |num| {
std.debug.print("{} ", .{num});
}
std.debug.print("\n");
}字符串处理
zig
const std = @import("std");
fn countVowels(text: []const u8) u32 {
var count: u32 = 0;
const vowels = "aeiouAEIOU";
for (text) |char| {
for (vowels) |vowel| {
if (char == vowel) {
count += 1;
break;
}
}
}
return count;
}
pub fn main() void {
const text = "Hello, World!";
const vowel_count = countVowels(text);
std.debug.print("文本 \"{s}\" 中有 {} 个元音字母\n", .{ text, vowel_count });
}循环的最佳实践
1. 选择合适的循环类型
zig
const std = @import("std");
pub fn main() void {
const data = [_]i32{ 1, 2, 3, 4, 5 };
// ✅ 遍历已知集合时使用 for
std.debug.print("使用 for 遍历数组: ");
for (data) |value| {
std.debug.print("{} ", .{value});
}
std.debug.print("\n");
// ✅ 条件循环时使用 while
var i: i32 = 0;
std.debug.print("使用 while 条件循环: ");
while (i < 5) : (i += 1) {
std.debug.print("{} ", .{i});
}
std.debug.print("\n");
}2. 避免无限循环
zig
const std = @import("std");
pub fn main() void {
var attempts: i32 = 0;
const max_attempts = 10;
// ✅ 好的做法:有明确的退出条件
while (attempts < max_attempts) : (attempts += 1) {
// 模拟某种操作
if (attempts == 3) {
std.debug.print("操作成功,退出循环\n", .{});
break;
}
std.debug.print("尝试 {}\n", .{attempts + 1});
}
if (attempts >= max_attempts) {
std.debug.print("达到最大尝试次数\n", .{});
}
}3. 合理使用循环控制语句
zig
const std = @import("std");
pub fn main() void {
const numbers = [_]i32{ 1, -2, 3, -4, 5, 0, 6 };
var positive_sum: i32 = 0;
for (numbers) |number| {
// 跳过负数
if (number < 0) continue;
// 遇到0时停止
if (number == 0) break;
positive_sum += number;
}
std.debug.print("正数和: {}\n", .{positive_sum});
}实践练习
练习 1:数字处理
zig
const std = @import("std");
pub fn main() void {
// TODO: 使用循环完成以下任务:
// 1. 计算 1 到 100 的和
// 2. 找出 1 到 50 中所有的质数
// 3. 计算斐波那契数列的前 10 项
}练习 2:数组操作
zig
const std = @import("std");
pub fn main() void {
var numbers = [_]i32{ 64, 34, 25, 12, 22, 11, 90 };
// TODO: 实现冒泡排序算法
// TODO: 找出数组中的最大值和最小值
// TODO: 计算数组的平均值
}练习 3:模式匹配
zig
const std = @import("std");
pub fn main() void {
const text = "Hello, World! This is a test.";
// TODO: 统计每个字符出现的次数
// TODO: 找出最长的单词
// TODO: 反转字符串中的每个单词
}总结
本章详细介绍了 Zig 中的循环结构:
- ✅
while循环:条件循环,支持继续表达式 - ✅
for循环:遍历数组、切片等可迭代对象 - ✅ 循环控制:
break和continue语句 - ✅ 嵌套循环和标签控制
- ✅ 循环表达式和返回值
- ✅ 编译时循环和优化
- ✅ 实际应用和最佳实践
掌握循环是编程的基本技能,它们是实现重复操作和数据处理的重要工具。在下一章中,我们将学习 Zig 的流程控制语句。