switch

switch

switch.zig

const assert = @import("std").debug.assert;
const builtin = @import("builtin");

test "switch simple" {
    const a: u64 = 10;
    const zz: u64 = 103;

    // All branches of a switch expression must be able to be coerced to a
    // common type.
    //
    // Branches cannot fallthrough. If fallthrough behavior is desired, combine
    // the cases and use an if.
    const b = switch (a) {
        // Multiple cases can be combined via a ','
        1, 2, 3 => 0,

        // Ranges can be specified using the ... syntax. These are inclusive
        // both ends.
        5...100 => 1,

        // Branches can be arbitrarily complex.
        101 => blk: {
            const c: u64 = 5;
            break :blk c * 2 + 1;
        },

        // Switching on arbitrary expressions is allowed as long as the
        // expression is known at compile-time.
        zz => zz,
        comptime blk: {
            const d: u32 = 5;
            const e: u32 = 100;
            break :blk d + e;
        } => 107,

        // The else branch catches everything not already captured.
        // Else branches are mandatory unless the entire range of values
        // is handled.
        else => 9,
    };

    assert(b == 1);
}

// Switch expressions can be used outside a function:
const os_msg = switch (builtin.os) {
    builtin.Os.linux => "we found a linux user",
    else => "not a linux user",
};

// Inside a function, switch statements implicitly are compile-time
// evaluated if the target expression is compile-time known.
test "switch inside function" {
    switch (builtin.os) {
        builtin.Os.fuchsia => {
            // On an OS other than fuchsia, block is not even analyzed,
            // so this compile error is not triggered.
            // On fuchsia this compile error would be triggered.
            @compileError("fuchsia not supported");
        },
        else => {},
    }
}
``` ```
$ zig test switch.zig
1/2 test "switch simple"...OK
2/2 test "switch inside function"...OK
All tests passed.

switch can be used to capture the field values of a Tagged union. Modifications to the field values can be done by placing a * before the capture variable name, turning it into a pointer.

test.zig

const assert = @import("std").debug.assert;

test "switch on tagged union" {
    const Point = struct {
        x: u8,
        y: u8,
    };
    const Item = union(enum) {
        A: u32,
        C: Point,
        D,
        E: u32,
    };

    var a = Item{ .C = Point{ .x = 1, .y = 2 } };

    // Switching on more complex enums is allowed.
    const b = switch (a) {
        // A capture group is allowed on a match, and will return the enum
        // value matched. If the payload types of both cases are the same
        // they can be put into the same switch prong.
        Item.A, Item.E => |item| item,

        // A reference to the matched value can be obtained using `*` syntax.
        Item.C => |*item| blk: {
            item.*.x += 1;
            break :blk 6;
        },

        // No else is required if the types cases was exhaustively handled
        Item.D => 8,
    };

    assert(b == 6);
    assert(a.C.x == 2);
}
``` ```
$ zig test test.zig
1/1 test "switch on tagged union"...OK
All tests passed.

See also:

  • comptime
  • enum
  • @compileError
  • Compile Variables

Exhaustive Switching

When a switch expression does not have an else clause, it must exhaustively list all the possible values. Failure to do so is a compile error:

test.zig

const Color = enum {
    Auto,
    Off,
    On,
};

test "exhaustive switching" {
    const color = Color.Off;
    switch (color) {
        Color.Auto => {},
        Color.On => {},
    }
}
``` ```
$ zig test test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:9:5: error: enumeration value 'Color.Off' not handled in switch
    switch (color) {
    ^

Switching with Enum Literals

Enum Literals can be useful to use with switch to avoid repetitively specifying enum or union types:

test.zig

const std = @import("std");
const assert = std.debug.assert;

const Color = enum {
    Auto,
    Off,
    On,
};

test "enum literals with switch" {
    const color = Color.Off;
    const result = switch (color) {
        .Auto => false,
        .On => false,
        .Off => true,
    };
    assert(result);
}
``` ```
$ zig test test.zig
1/1 test "enum literals with switch"...OK
All tests passed.