⚡ Zig Guide LiveUnofficial
✓ Zig 0.17.0-dev.1454+5faa79730On an older Zig?

Labelled Blocks

const std = @import("std");
const expect = std.testing.expect;

test "block as an expression" {
    // `break :label value` yields a value from the labelled block, so a
    // multi-step computation can still produce a single const.
    const count = blk: {
        var sum: u32 = 0;
        for (0..10) |i| sum += i;
        break :blk sum;
    };
    try expect(count == 45);
    try expect(@TypeOf(count) == u32);
}

test "labels also name scopes for shadowing" {
    const outer_value: u32 = 1;
    const result = blk: {
        const outer_value_inner: u32 = 2;
        break :blk outer_value + outer_value_inner;
    };
    try expect(result == 3);
}

Label a block and break out of it with a value:

const count = blk: {
    var sum: u32 = 0;
    for (0..10) |i| sum += i;
    break :blk sum;
};

The name blk is arbitrary. What matters is that a multi-statement computation still produces a single const, so the intermediate var cannot leak into the surrounding scope or be accidentally reused later.

This is the Zig answer to “I need a few lines to compute this, but I want the result to be immutable”, a pattern that otherwise pushes people toward a mutable variable with a wider scope than it deserves, or a single-use function.