for Loops
A for loop visits the elements of an array, slice, or range.
const std = @import("std");
pub fn main() void {
const data = [_]u8{ 10, 20, 30 };
for (data) |x| {
std.debug.print("{d}\n", .{x});
}
}The output is:
10
20
30The name between bars is the loop capture.
|x|On each iteration, x is the current element.
A for loop over an array visits each element in order.
const letters = [_]u8{ 'a', 'b', 'c' };
for (letters) |ch| {
std.debug.print("{c}\n", .{ch});
}A string literal is an array of bytes, so a loop over a string visits bytes.
for ("zig") |b| {
std.debug.print("{c}\n", .{b});
}This prints:
z
i
gThis is byte iteration. It is not Unicode character iteration. A UTF-8 character may use more than one byte.
A for loop can also capture the index.
const data = [_]u8{ 10, 20, 30 };
for (data, 0..) |x, i| {
std.debug.print("{d}: {d}\n", .{ i, x });
}The output is:
0: 10
1: 20
2: 30The expression 0.. is an open-ended range. In this loop, Zig pairs it with data, so it gives the indices 0, 1, and 2.
A closed range has both ends.
for (0..5) |i| {
std.debug.print("{d}\n", .{i});
}This prints:
0
1
2
3
4The end is not included.
A for loop can iterate over more than one sequence at the same time.
const names = [_][]const u8{ "red", "green", "blue" };
const values = [_]u8{ 1, 2, 3 };
for (names, values) |name, value| {
std.debug.print("{s}: {d}\n", .{ name, value });
}All sequences must have the same length, unless one of them is an open-ended range used for indexing.
Use a pointer capture to modify elements.
var data = [_]u8{ 1, 2, 3 };
for (&data) |*x| {
x.* += 1;
}After the loop, data is:
[_]u8{ 2, 3, 4 }The &data passes a pointer to the array. The capture |*x| captures a pointer to each element. The expression x.* means the value pointed to by x.
Without pointer capture, the loop gets a copy of each element.
var data = [_]u8{ 1, 2, 3 };
for (data) |x| {
_ = x + 1;
}This does not change data.
Use break to leave a for loop.
const data = [_]u8{ 5, 8, 13, 21 };
for (data) |x| {
if (x == 13) break;
std.debug.print("{d}\n", .{x});
}This prints:
5
8Use continue to skip one iteration.
const data = [_]u8{ 1, 2, 3, 4, 5 };
for (data) |x| {
if (x % 2 == 0) continue;
std.debug.print("{d}\n", .{x});
}This prints:
1
3
5Like while, a for loop may have an else branch. The else branch runs only if the loop finishes normally.
const data = [_]u8{ 1, 2, 3 };
for (data) |x| {
if (x == 9) break;
} else {
std.debug.print("not found\n", .{});
}The loop does not break, so the else branch runs.
A for loop can produce a value.
const data = [_]u8{ 4, 7, 9, 12 };
const found = for (data, 0..) |x, i| {
if (x == 9) break i;
} else null;The value of found is 2. If no element equals 9, the value is null.
This is a compact search pattern.
const index = for (data, 0..) |x, i| {
if (x == target) break i;
} else null;The type of index is ?usize.
Use for when the number of iterations comes from the data. Use while when the loop is controlled by a condition that changes in a less regular way.
for (items) |item| {
use(item);
}This says: visit every item.
while (readNext()) |item| {
use(item);
}This says: keep going while another item can be read.
Exercise 3-17. Write a for loop that prints every element in an array.
Exercise 3-18. Print each element with its index.
Exercise 3-19. Use pointer capture to double every number in an array.
Exercise 3-20. Write a for expression that returns the index of the first even number, or null if there is none.