Building Blocks Of Zig: Unions

Dayvster 🌊 - Jun 29 - - Dev Community

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 };
Enter fullscreen mode Exit fullscreen mode

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,
};
Enter fullscreen mode Exit fullscreen mode

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});
  },
}

Enter fullscreen mode Exit fullscreen mode

Conclusion

So there it is, we've learned about Zig unions and how they can be used to define types that can have multiple possible value types, I know it may seem a bit confusing at first but once you get the hang of it you'll see how powerful unions can be. I'd recommend using them whenever you are dealing with values that can have multiple different possible types, such as: configuration values, user input, API's with different return types for the same field etc. etc.

I hope you enjoyed this post and learned something new about Zig. If you have any questions or comments feel free to reach out to me on Twitter

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .