For Loops
const std = @import("std");
const expect = std.testing.expect;
test "iterate values" {
const string = [_]u8{ 'a', 'b', 'c' };
var count: usize = 0;
for (string) |character| {
if (character == 'b') count += 1;
}
try expect(count == 1);
}
test "iterate with an index" {
const string = [_]u8{ 'a', 'b', 'c' };
var last_index: usize = 0;
for (string, 0..) |_, index| {
last_index = index;
}
try expect(last_index == 2);
}
test "ranges" {
var sum: usize = 0;
for (0..5) |i| sum += i;
try expect(sum == 10);
}
test "iterate two sequences at once" {
// Multi-object `for` requires equal lengths; a mismatch is checked.
const names = [_][]const u8{ "a", "b" };
const scores = [_]u8{ 1, 2 };
var total: u8 = 0;
for (names, scores) |name, score| {
_ = name;
total += score;
}
try expect(total == 3);
}
test "mutate through a pointer capture" {
var numbers = [_]u8{ 1, 2, 3 };
for (&numbers) |*n| n.* *= 2;
try expect(numbers[2] == 6);
}Zig’s for iterates over something: a slice, an array, a range. There is no
three-clause for (i = 0; i < n; i++); that is what while is for. The result
is that the common case carries no opportunity for an off-by-one.
Indices are opt-in
for (items, 0..) |item, index| { ... }
The 0.. is a second sequence to iterate in lockstep, not special syntax. You
only pay for the index when you ask for it.
Iterating several sequences together
The same mechanism zips any number of sequences:
for (names, scores) |name, score| { ... }
Lengths must match. A mismatch is checked, so this cannot silently read past the end of the shorter one.
Mutating in place
Capturing by value gives you a copy. To modify the underlying elements, iterate over a pointer to the array and capture by pointer:
for (&numbers) |*n| n.* *= 2;