const A = struct {
x: B,
// y: @TypeOf(x.foo), // not compile
// z: @TypeOf(A{}.x.foo), // not compile
w: @TypeOf(B.foo), // compiles, but looks not right
};
const B = union(enum) {
foo: struct {
a: u32,
},
bar: struct {
b: u64,
},
};
Never mind, figured it out.
const T = @typeInfo(B).Union.fields[@intFromEnum(B.foo)].type;
But could anyone confirm that whether or not @TypeOf(B.foo)
should compile?
Is there @intFromEnum
alike builtin function to get the index of a struct field?
Out of curiosity, what is wrong with @TypeOf(B.foo)
?
Because foo
is a field, not a declaration. What compiles should be aValueOfB.foo
,
const std = @import("std");
const B = union(enum) {
foo: struct {
a: u32,
},
bar: struct {
b: u64,
},
};
const T = @TypeOf(B.foo); // not compile here
pub fn main() !void {
var x: T = undefined;
x = .{.a = 123};
std.debug.print("{}\n", .{x});
}
There’s a helper function in the standard library which does what you’re looking for here: std.meta.FieldType(B, .foo)
B.foo
is indeed meant to compile, but it’s not doing what you think. Tagged unions have an underlying “tag type”, which is inferred when you write union(enum)
- in this case it’s basically enum { foo, bar }
. UnionType.foo
is allowed as a convenient shorthand for constructing values of this tag type - union values coerce to their tag, and fields with a void
payload can be coerced to from their tag. (That is, MyUnion.my_tag
coerces to MyUnion{ .my_tag = {} }
.)
If you do @compileLog(B.foo)
you’ll see that it has type @typeInfo(main.B).Union.tag_type.?
, which is just how the automatically-generated tag type is written.
Thanks very much for the explanations. Not aware of that the meta
module also provides some reflection functionalities.