Enums
const std = @import("std");
const expect = std.testing.expect;
const Direction = enum { north, south, east, west };
// The tag type can be pinned, which fixes the numeric values.
const Value = enum(u8) { zero = 0, one = 1, hundred = 100 };
const Suit = enum {
clubs,
spades,
diamonds,
hearts,
// Enums can have methods; they are namespaced functions, not vtables.
pub fn isRed(self: Suit) bool {
return switch (self) {
.diamonds, .hearts => true,
.clubs, .spades => false,
};
}
};
test "enum values" {
try expect(@intFromEnum(Value.zero) == 0);
try expect(@intFromEnum(Value.hundred) == 100);
}
test "inferred enum literals" {
// When the type is known, `.north` is enough.
const d: Direction = .north;
try expect(d == Direction.north);
}
test "enum methods" {
try expect(Suit.hearts.isRed());
try expect(!Suit.spades.isRed());
}
test "enums expose their tags at comptime" {
const info = @typeInfo(Direction).@"enum";
// Names and values are parallel arrays, not one array of field structs.
try expect(info.field_names.len == 4);
try expect(info.field_values.len == info.field_names.len);
try expect(std.mem.eql(u8, info.field_names[2], "east"));
try expect(info.tag_type == u2);
try expect(info.mode == .exhaustive);
try expect(std.mem.eql(u8, @tagName(Direction.east), "east"));
}Inferred literals
When the expected type is known, the leading dot is enough:
const d: Direction = .north;
takeDirection(.south);
This keeps switch prongs and struct literals readable without repeating the
type name everywhere.
Pinning the representation
const Value = enum(u8) { zero = 0, one = 1, hundred = 100 };
Specifying the tag type fixes both the size and the numeric values, which
matters for wire formats and C interop. Convert with @intFromEnum and
@enumFromInt. The latter is checked in safety builds, because not every
integer is a valid tag.
Methods
Enums can declare functions. Suit.hearts.isRed() is exactly
Suit.isRed(Suit.hearts): method syntax is sugar for passing the receiver as
the first argument. There is no dynamic dispatch and no vtable.
Reflection
@typeInfo(T).@"enum" exposes the tags at comptime:
const info = @typeInfo(Direction).@"enum";
info.field_names[2]; // "east"
info.field_values[2]; // 2
info.tag_type; // u2
info.mode; // .exhaustive
Note these are parallel arrays, not one array of field structs. Older
tutorials show info.fields[i].name; that shape is gone. The split landed
between 0.17.0-dev.644 and dev.1441, and was the only break across all 53
snippets in this guide when the compiler was updated.
@tagName gives the name as a string. Together this is how generic code prints
or parses enums without a hand-written table.