Skip to content

`break`, `continue`, and Labels

break leaves a loop.

break, continue, and Labels

break leaves a loop.

var i: usize = 0;

while (i < 10) : (i += 1) {
    if (i == 5) break;
    std.debug.print("{d}\n", .{i});
}

This prints:

0
1
2
3
4

When i becomes 5, the loop ends.

continue skips the rest of the current iteration and starts the next one.

var i: usize = 0;

while (i < 10) : (i += 1) {
    if (i % 2 == 0) continue;
    std.debug.print("{d}\n", .{i});
}

This prints:

1
3
5
7
9

In a while loop with a continue expression, continue still runs the continue expression.

while (i < 10) : (i += 1) {
    if (i < 5) continue;
    std.debug.print("{d}\n", .{i});
}

The update i += 1 is still performed.

A loop can have a label.

outer: while (true) {
    while (true) {
        break :outer;
    }
}

The label is written before the loop name. break :outer leaves the loop named outer, not just the inner loop.

Labels are useful with nested loops.

const table = [_][3]u8{
    .{ 1, 2, 3 },
    .{ 4, 5, 6 },
    .{ 7, 8, 9 },
};

const target: u8 = 5;

var row: usize = 0;
var col: usize = 0;

search: for (table, 0..) |line, r| {
    for (line, 0..) |value, c| {
        if (value == target) {
            row = r;
            col = c;
            break :search;
        }
    }
}

Without the label, break would leave only the inner loop. With the label, it leaves the whole search.

continue can also use a label.

outer: for (0..3) |i| {
    for (0..3) |j| {
        if (j == 1) continue :outer;
        std.debug.print("{d},{d}\n", .{ i, j });
    }
}

The output is:

0,0
1,0
2,0

When j is 1, the program continues the outer loop.

A labeled break may give a value to a loop expression.

const data = [_]u8{ 3, 8, 13, 21 };

const found = search: for (data, 0..) |x, i| {
    if (x == 13) break :search i;
} else null;

The value of found is 2.

The label names the expression that receives the value.

The same idea works with blocks.

const x = blk: {
    const a = 10;
    const b = 20;
    break :blk a + b;
};

Here break :blk gives a value to the block.

For loops, break and else work together. The else branch runs only when the loop ends normally.

const found = for (data, 0..) |x, i| {
    if (x == target) break i;
} else null;

If target is found, break i gives the index. If the loop finishes without a break, the else branch gives null.

The same rule applies to while.

var i: usize = 0;

const found = while (i < data.len) : (i += 1) {
    if (data[i] == target) break i;
} else null;

A plain break gives no value. It is used when the loop result is not needed.

while (true) {
    if (done()) break;
}

A value break is used when the loop itself computes something.

const index = for (data, 0..) |x, i| {
    if (x == target) break i;
} else null;

Prefer plain break for control flow. Prefer value break when the loop is naturally a search, selection, or computation.

Exercise 3-21. Write a loop that stops when it finds zero.

Exercise 3-22. Write a loop that skips negative numbers and prints the rest.

Exercise 3-23. Write nested loops that search a two-dimensional array.

Exercise 3-24. Rewrite the nested search using a labeled break.