Enums

An enum is a custom type with a fixed list of pre-defined values (called fields or tags):

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

const Color = enum {
    red,
    green,
    blue,

    fn isRed(self: Color) bool {
        return self == .red;
    }
};

pub fn main() void {
    // Two ways to initialize an enum:
    const a = Color.green;
    const b: Color = .green;

    // Print with {}, or {t} to get just the tag.
    print("a is {}\n", .{a});
    print("b is {t}\n", .{b});
    print("a is red? {}\n", .{a.isRed()});

    if (a == .green)
        print("a is green\n", .{});
    const color_code: u24 = switch (a) {
        .red => 0xcc0000,
        .green => 0x66cc00,
        .blue => 0x0000ff,
    };
    print("color code: {X:06}\n", .{color_code});
}
$ zig run enums.zig
a is .green
b is green
a is red? false
a is green
color code: 66CC00

Ordinal values

Each tag of an enum is assigned a small integer value. By default, they’re numbered starting from 0:

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

const Color = enum { red, green, blue };

pub fn main() void {
    print("tag type: {}\n", .{
        @TypeOf(@intFromEnum(Color.red)),
    });
    print("ordinal values: {} {} {}\n", .{
        @intFromEnum(Color.red),
        @intFromEnum(Color.green),
        @intFromEnum(Color.blue),
    });
    const c: Color = @enumFromInt(2);
    print("color 2 is {t}\n", .{c});
}
$ zig run enums-2.zig 
tag type: u2
ordinal values: 0 1 2
color 2 is blue

We can override the ordinal type and values:

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

const Color = enum(u24) {
    red = 0xcc0000,
    green = 0x66cc00,
    blue = 0x0000ff,
};

pub fn main() void {
    print("ordinal type: {}\n", .{
        @TypeOf(@intFromEnum(Color.red)),
    });
    print("ordinal values: {X:06} {X:06} {X:06}\n", .{
        @intFromEnum(Color.red),
        @intFromEnum(Color.green),
        @intFromEnum(Color.blue),
    });
}
$ zig run enums-3.zig 
ordinal type: u24
ordinal values: CC0000 66CC00 0000FF

Adding a _ tag makes an enum a non-exhaustive enum, which means it can have any ordinal value:

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

const Color = enum(u24) {
    red = 0xcc0000,
    green = 0x66cc00,
    blue = 0x0000ff,
    _,

    fn frenchName(self: Color) []const u8 {
        return switch (self) {
            .red => "rouge",
            .green => "vert",
            .blue => "bleu",
            _ => "couleur mystérieuse",
        };
    }
};

pub fn main() void {
    const a: Color = .green;
    const b: Color = @enumFromInt(0xffffff);
    print("{}: {s}\n", .{ a, a.frenchName() });
    print("{}: {s}\n", .{ b, b.frenchName() });
}
$ zig run non-exhaustive.zig 
.green: vert
@enumFromInt(16777215): couleur mystérieuse

Next example: Unions.