Labeled Switch
The switch statement in Zig has
an unusual feature: if we add a label, we can use continue
to jump back to the start of the switch. It becomes a loop and a switch
in one.
The following example is a very simple virtual machine. It runs a sequence of instructions that modify a number and prints the result:
const std = @import("std");
const print = std.debug.print;
const Instruction = enum {
increment, // increment the number
decrement, // decrement the number
skip, // skip the next instruction
halt, // stop the virtual machine
};
pub fn main() void {
// the instructions to be interpreted
const instructions = [_:.halt]Instruction{
.increment,
.skip,
.decrement,
.increment,
};
// initial state
var state: i64 = 0;
// process the instructions
var index: u64 = 0;
sw: switch (instructions[index]) {
.increment => {
state += 1;
index += 1;
continue :sw instructions[index];
},
.decrement => {
state -= 1;
index += 1;
continue :sw instructions[index];
},
.skip => {
index += 2;
continue :sw instructions[index];
},
.halt => {},
}
// print the result
print("Result: {}\n", .{state});
}We’re using a sentinel-terminated array to
make sure the last instruction is always halt.
$ zig run labeled-switch.zig
Result: 2
Switch expressions
The next example uses switch as an expression:
const std = @import("std");
const print = std.debug.print;
const expect = std.testing.expect;
const State = enum {
start,
first_digit,
more_digits,
};
// parseNumber returns true if the input can be parsed.
fn parseNumber(input: [*:0]const u8) bool {
var index: u64 = 0;
return sw: switch (State.start) {
.start => {
switch (input[index]) {
'+', '-' => {
index += 1;
continue :sw .first_digit;
},
'0'...'9' => {
continue :sw .first_digit;
},
else => {
// Use 'break' to yield a value:
break :sw false;
},
}
},
.first_digit => {
switch (input[index]) {
'0'...'9' => {
index += 1;
continue :sw .more_digits;
},
else => {
break :sw false;
},
}
},
.more_digits => {
switch (input[index]) {
0 => {
break :sw true;
},
'0'...'9' => {
index += 1;
continue :sw .more_digits;
},
else => {
break :sw false;
},
}
},
};
}
test "parseNumber returns true for valid integer" {
try expect(parseNumber("123"));
try expect(parseNumber("+123"));
try expect(parseNumber("-123"));
}
test "parseNumber returns false for invalid integer" {
try expect(!parseNumber(""));
try expect(!parseNumber("+"));
try expect(!parseNumber("abc"));
try expect(!parseNumber("-x"));
try expect(!parseNumber("1y"));
}$ zig test labeled-switch-2.zig
All 2 tests passed.
This is the last example for now.