const expect = @import("std").testing.expect; // Zig's unions allow you to define types that store one value of many possible typed fields; // only one field may be active at one time. // Bare union types do not have a guaranteed memory layout. // Because of this, bare unions cannot be used to reinterpret memory. // Accessing a field in a union that is not active is detectable illegal behaviour. const Result = union { int: i64, float: f64, bool: bool, }; test "simple union" { var result = Result{ .int = 1234 }; result.float = 12.34; // test "simple union"...access of inactive union field // .\tests.zig:342:12: 0x7ff62c89244a in test "simple union" (test.obj) // result.float = 12.34; // ^ } // Tagged unions are unions that use an enum to detect which field is active. // Here we make use of payload capturing again, // to switch on the tag type of a union while also capturing the value it contains. // Here we use a pointer capture; captured values are immutable, // but with the `|*value|` syntax, we can capture a pointer to the values instead of the values themselves. // This allows us to use dereferencing to mutate the original value. const Tag = enum { a, b, c }; const Tagged = union(Tag) { a: u8, b: f32, c: bool }; test "switch on tagged union" { var value = Tagged{ .b = 1.5 }; switch (value) { .a => |*byte| byte.* += 1, .b => |*float| float.* *= 2, .c => |*b| b.* = !b.*, } try expect(value.b == 3); } // The tag type of a tagged union can also be inferred. This is equivalent to the Tagged type above. // const Tagged = union(enum) { a: u8, b: f32, c: bool }; // `void` member types can have their type omitted from the syntax. Here, `none` is of type `void`. const Tagged2 = union(enum) { a: u8, b: f32, c: bool, none };