Search code examples
enumszig

In Zig, what is the right way to iterate over the fields of an enum?


I'm trying to iterate over all the fields in an Enum (really I just want to the values), in my enum in Zig:

const std = @import("std");

const MyEnum = enum(u8) {
    NONE = 0,
    ONE,
    TWO,
};

pub fn main() void {
    std.debug.assert(@typeInfo(MyEnum).Enum.fields.len == 3);
    std.debug.assert(std.mem.eql(u8, @typeInfo(MyEnum).Enum.fields[0].name, "NONE"));
    std.debug.assert(@typeInfo(MyEnum).Enum.fields[0].value == 0);

    for (std.meta.fields(MyEnum)) |f| {
        std.debug.print("{}\n", .{ f.value });
    }

    for (@typeInfo(MyEnum).Enum.fields) |f| {
        std.debug.print("{}\n", .{ f.value });
    }
}

The asserts at the top just show I've got the basics right. Neither of the for loops compile, I get:

... error: values of type '[]const builtin.Type.EnumField' must be comptime-known, but index value is runtime-known

AFAICT, all the content of the enum is "comptime-known", so I'm not sure why the error is complaining about EnumField...

I'm running a locally-built zig 0.12.0-dev.1782+dd188307b sync'd in the last couple of days.


Solution

  • The error message is not very good because it's actually coming from your for statement. It's the index that statement uses that's not comptime known. Use inline for instead to run the loop at compile time:

    const std = @import("std");
    
    const MyEnum = enum(u8) {
        NONE = 0,
        ONE,
        TWO,
    };
    
    pub fn main() void {
        std.debug.assert(@typeInfo(MyEnum).Enum.fields.len == 3);
        std.debug.assert(std.mem.eql(u8, @typeInfo(MyEnum).Enum.fields[0].name, "NONE"));
        std.debug.assert(@typeInfo(MyEnum).Enum.fields[0].value == 0);
    
        inline for (std.meta.fields(MyEnum)) |f| {
            std.debug.print("{}\n", .{f.value});
        }
    
        inline for (@typeInfo(MyEnum).Enum.fields) |f| {
            std.debug.print("{}\n", .{f.value});
        }
    }