Search code examples
initializationmetaprogrammingzig

How can I initialize a union(enum) given a comptime string specifying the member in Zig?


Zig has the @field builtin which allows you to access a struct/union/enum member given a comptime string field name.

E.g., as given by the above link,

var p = Point{ .x = 0, .y = 0 };

@field(p, "x") = 4;
@field(p, "y") = @field(p, "x") + 1;

However, for my specific application, I need to be able to initialize a union(enum) given a comptime []const u8, and I would prefer not to do this with an if-else if-tree to prevent verbosity.

I imagine something much like JavaScript's ["<field-name>"] member accessing but with static instead of dynamic strings:

const c = MonochromaticColor{ ["r"] = 255 }; // "MonochromaticColor" is a contrived enum

One can emulate the fanciful structure initialization

const p = Point{ ["x"] = 4, ["y"] = 5 };

with

var p: Point = undefined;
@field(p, "x") = 4;
@field(p, "y") = 5;

the trivial disparities between the two notwithstanding.

However, this does not appear to be possible (at least I wasn't able to get it to work) with union(enum)s. In any case, I would prefer to avoid the above compromise.

How can I initialize a union(enum) given a comptime string specifying the member in Zig?


Solution

  • This can be done via the @unionInit builtin.

    const std = @import("std");
    
    const Ex = union(enum) { A: u32, B: []const u8 };
    
    pub fn main() void {
        const example = @unionInit(Ex, "B", "example");
        std.log.info("Example: {any}", .{example});
    }
    

    Outputs:

    info: Example: test.Ex{ .B = { 101, 120, 97, 109, 112, 108, 101 } }