Building Blocks Of Zig: Unions
What are Zig Unions?
Zig unions are a way to represent a type that can be one of several different types. However only one of the types can be active at any given time. Think of it as a way to represent multiple possible types of a value in a single variable.
That may sound a bit confusing at first but it is actually quite simple. Let's take a look at an example to understand how Zig unions work.
How To Create A Union In Zig
Creating a union in Zig is similar to how you would define a struct.
const ValidInput = union {
int: i32,
string: []const u8,
float: f32,
};
// And to use the union we simply:
const input = ValidInput{ .int = 42 };
This is what we call a Bare Union. It is a union that does not have a tag, this means that the memory layout of the union is not necessarily the same across the board. This is essentially because a bare union does not have a tag to tell us which field is active. So accessing a field in the union that is not active will result in a problem.
What is a Tagged Union in Zig?
A tagged union is a union that has a tag. For this we use an enum
to define the tag. This way we can tell which field is currently active in the union.
const Tag = enum {
Int,
String,
Float,
};
const TaggedValidInput = union(Tag) {
Int: i32,
String: []const u8,
Float: f32,
};
As you see in the example above we define an enum
called Tag
that has three possible values Int
, String
and Float
. We then define a union called TaggedValidInput
that uses the Tag
enum as a tag. This way we can tell which field is active in the union.
That's pretty nifty right? Now here's the cool part, we can use the switch
statement to check which field is active in the union and act accordingly.
const input = TaggedValidInput{ .Int = 42 };
switch (input) {
.Int => {
std.log.info("Int: {d}\n", .{input.Int});
},
.String => {
std.log.info("String: {s}\n", .{input.String});
},
.Float => {
std.log.info("Float: {f}\n", .{input.Float});
},
}