# `break` and `continue`

### `break` and `continue`

Loops repeat code. But sometimes you do not want a loop to finish in the normal way.

You may want to stop early.

You may want to skip one item.

You may want to leave an outer loop from inside an inner loop.

Zig gives you two simple tools for this:

```zig
break
```

and:

```zig
continue
```

`break` exits a loop.

`continue` skips to the next loop iteration.

#### `break` Stops a Loop

Here is a simple loop:

```zig
const std = @import("std");

pub fn main() void {
    var i: u8 = 0;

    while (i < 10) : (i += 1) {
        if (i == 4) {
            break;
        }

        std.debug.print("{}\n", .{i});
    }
}
```

This prints:

```text
0
1
2
3
```

The loop would normally continue until `i` reaches `10`.

But this branch stops it early:

```zig
if (i == 4) {
    break;
}
```

When `i` becomes `4`, `break` runs. The loop ends immediately.

The print statement does not run for `4`.

#### `break` in a `for` Loop

`break` works in `for` loops too.

```zig
const std = @import("std");

pub fn main() void {
    const numbers = [_]u8{ 10, 20, 30, 40 };

    for (numbers) |n| {
        if (n == 30) {
            break;
        }

        std.debug.print("{}\n", .{n});
    }
}
```

This prints:

```text
10
20
```

The loop stops when it reaches `30`.

This is useful for search logic. Once you find what you want, there is no reason to keep looping.

#### `continue` Skips One Iteration

`continue` does not stop the whole loop.

It skips the rest of the current iteration and moves to the next one.

```zig
const std = @import("std");

pub fn main() void {
    var i: u8 = 0;

    while (i < 6) : (i += 1) {
        if (i == 3) {
            continue;
        }

        std.debug.print("{}\n", .{i});
    }
}
```

This prints:

```text
0
1
2
4
5
```

When `i` is `3`, this line runs:

```zig
continue;
```

The rest of the loop body is skipped.

So this line does not run for `3`:

```zig
std.debug.print("{}\n", .{i});
```

Then the loop continues with the next value.

#### `continue` in a `while` Loop with a Continue Expression

Remember this form:

```zig
while (condition) : (update) {
    // body
}
```

The update part still runs after `continue`.

Example:

```zig
const std = @import("std");

pub fn main() void {
    var i: u8 = 0;

    while (i < 5) : (i += 1) {
        if (i == 2) {
            continue;
        }

        std.debug.print("{}\n", .{i});
    }
}
```

This prints:

```text
0
1
3
4
```

When `i == 2`, `continue` runs. Zig skips the print, then runs:

```zig
i += 1
```

So the loop still moves forward.

This is important. Without the continue expression, you could accidentally create an infinite loop.

#### A Common Mistake

This loop never ends:

```zig
var i: u8 = 0;

while (i < 5) {
    if (i == 2) {
        continue;
    }

    i += 1;
}
```

When `i` becomes `2`, the loop reaches `continue`.

That skips:

```zig
i += 1;
```

So `i` stays `2` forever.

A safer version is:

```zig
var i: u8 = 0;

while (i < 5) : (i += 1) {
    if (i == 2) {
        continue;
    }
}
```

Now the update happens even when `continue` is used.

#### Skipping Items with `continue`

`continue` is useful when some items should be ignored.

```zig
const std = @import("std");

pub fn main() void {
    const numbers = [_]u8{ 1, 2, 3, 4, 5, 6 };

    for (numbers) |n| {
        if (n % 2 == 0) {
            continue;
        }

        std.debug.print("{}\n", .{n});
    }
}
```

This prints:

```text
1
3
5
```

The expression:

```zig
n % 2 == 0
```

checks whether `n` is even.

If it is even, the loop skips it.

So only odd numbers are printed.

#### Searching with `break`

`break` is useful when searching.

```zig
const std = @import("std");

pub fn main() void {
    const numbers = [_]u8{ 4, 8, 15, 16, 23, 42 };
    const target: u8 = 16;

    var found = false;

    for (numbers) |n| {
        if (n == target) {
            found = true;
            break;
        }
    }

    std.debug.print("found = {}\n", .{found});
}
```

This prints:

```text
found = true
```

The loop stops as soon as it finds the target.

That is better than checking the remaining items for no reason.

#### `break` Can Return a Value

In Zig, loops can be expressions.

That means `break` can return a value from a loop.

```zig
const std = @import("std");

pub fn main() void {
    const numbers = [_]u8{ 4, 8, 15, 16, 23, 42 };
    const target: u8 = 16;

    const found = for (numbers) |n| {
        if (n == target) {
            break true;
        }
    } else false;

    std.debug.print("found = {}\n", .{found});
}
```

This prints:

```text
found = true
```

Read this part carefully:

```zig
const found = for (numbers) |n| {
    if (n == target) {
        break true;
    }
} else false;
```

It means:

loop through the numbers

if `target` is found, stop and make the loop value `true`

if the loop finishes normally, use the `else` value `false`

So `found` becomes either `true` or `false`.

This is a clean Zig pattern for search code.

#### `break` Value Must Match the `else` Value

When a loop returns a value, the `break` value and the `else` value must have compatible types.

This is valid:

```zig
const result = for (items) |item| {
    if (item == target) {
        break true;
    }
} else false;
```

Both values are booleans.

This is invalid:

```zig
const result = for (items) |item| {
    if (item == target) {
        break true;
    }
} else "not found";
```

One value is a boolean. The other is a string.

Zig rejects this because `result` needs one clear type.

#### `break` from a Labeled Block

`break` can also leave a labeled block.

```zig
const std = @import("std");

pub fn main() void {
    const value = blk: {
        if (true) {
            break :blk 123;
        }

        break :blk 0;
    };

    std.debug.print("value = {}\n", .{value});
}
```

This prints:

```text
value = 123
```

The label is:

```zig
blk:
```

The line:

```zig
break :blk 123;
```

means:

leave the block named `blk` and make its value `123`.

This is not a loop. It is a labeled block expression.

#### `break` from an Outer Loop

Without labels, `break` exits the nearest loop.

```zig
for (0..3) |i| {
    for (0..3) |j| {
        if (j == 1) {
            break;
        }

        std.debug.print("i={}, j={}\n", .{ i, j });
    }
}
```

This prints:

```text
i=0, j=0
i=1, j=0
i=2, j=0
```

The `break` exits only the inner loop.

To exit the outer loop, use a label:

```zig
const std = @import("std");

pub fn main() void {
    outer: for (0..3) |i| {
        for (0..3) |j| {
            if (i == 1 and j == 1) {
                break :outer;
            }

            std.debug.print("i={}, j={}\n", .{ i, j });
        }
    }
}
```

This prints:

```text
i=0, j=0
i=0, j=1
i=0, j=2
i=1, j=0
```

The label is:

```zig
outer:
```

The line:

```zig
break :outer;
```

means:

leave the loop named `outer`.

#### `continue` to an Outer Loop

A labeled `continue` moves to the next iteration of a named loop.

```zig
const std = @import("std");

pub fn main() void {
    outer: for (0..3) |i| {
        for (0..3) |j| {
            if (j == 1) {
                continue :outer;
            }

            std.debug.print("i={}, j={}\n", .{ i, j });
        }
    }
}
```

This prints:

```text
i=0, j=0
i=1, j=0
i=2, j=0
```

When `j == 1`, this runs:

```zig
continue :outer;
```

That skips the rest of the inner loop and starts the next iteration of the outer loop.

Use labeled `continue` only when it makes the code clearer. In many cases, a helper function is easier to read.

#### Early Exit for Validation

`break` and `continue` are useful in validation code.

Suppose we want to check that all bytes are lowercase ASCII letters.

```zig
const std = @import("std");

fn isLowercaseAscii(text: []const u8) bool {
    for (text) |byte| {
        if (byte < 'a' or byte > 'z') {
            return false;
        }
    }

    return true;
}

pub fn main() void {
    const ok = isLowercaseAscii("zig");

    std.debug.print("ok = {}\n", .{ok});
}
```

This prints:

```text
ok = true
```

This example uses `return`, not `break`, because the loop is inside a function and the whole function can stop immediately.

But the idea is the same: once you know the answer, exit early.

#### Prefer Clear Exits

Early exits are useful, but too many can make code hard to follow.

This is usually clear:

```zig
for (items) |item| {
    if (!item.valid) {
        continue;
    }

    process(item);
}
```

The `continue` removes an unwanted case early.

This is also clear:

```zig
for (items) |item| {
    if (item.id == target_id) {
        break;
    }
}
```

The `break` stops after finding the target.

But deeply nested code with many labels can become difficult:

```zig
outer: for (a) |x| {
    middle: for (b) |y| {
        inner: for (c) |z| {
            if (some_condition) {
                break :outer;
            }
        }
    }
}
```

Sometimes this is correct. But often, a small helper function is better.

#### The Main Idea

`break` exits a loop.

`continue` skips the current iteration and moves to the next one.

Use `break` when the loop has done enough work.

Use `continue` when the current item should be ignored.

Use labels when you need to control an outer loop.

The beginner rule is simple: keep loop exits obvious. A reader should be able to see quickly why the loop stops or why an item is skipped.

