Learning Zig from the official language reference.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
zig-langref/unions.zig

127 lines
2.7 KiB

const std = @import("std");
const mem = std.mem;
const debug = std.debug;
const testing = std.testing;
const Payload = union {
int: i32,
float: f64,
bool: bool,
};
test "bare unions" {
var p = Payload{ .int = 42 };
testing.expect(p.int == 42);
p = Payload{ .float = 2.78128 };
testing.expect(p.float == 2.78128);
p = Payload{ .bool = false };
testing.expect(!p.bool);
}
const ComplexTagType = enum {
ok,
not_ok,
};
const ComplexType = union(ComplexTagType) {
ok: u8,
not_ok: void,
};
test "tagged union" {
var ok = ComplexType{ .ok = 42 };
testing.expect(ok.ok == 42);
// only tagged unions can be used with switch
const res = switch (ok) {
.ok => |val| val,
.not_ok => unreachable,
};
testing.expect(res == 42);
// tagged unions also coerce to their tag type
testing.expect(@as(ComplexTagType, ok) == .ok);
testing.expect(@as(ComplexTagType, ok) == ComplexTagType.ok);
}
test "get tag type" {
testing.expect(std.meta.Tag(ComplexType) == ComplexTagType);
}
test "coerce to enum" {
const c1 = ComplexType{ .ok = 42 };
const c2 = ComplexType.not_ok;
testing.expect(c1 == .ok);
testing.expect(c2 == .not_ok);
}
test "modify tagged union in a switch" {
var c = ComplexType{ .ok = 21 };
testing.expect(c.ok == 21);
switch (c) {
.ok => |*val| val.* += val.*,
else => unreachable,
}
testing.expect(c.ok == 42);
}
// wehy do this? well, because only tagged unions can be used with switch, for one
const Variant = union(enum) {
int: i32,
boolean: bool,
none,
pub fn truthy(self: Variant) bool {
return switch (self) {
.int => |val| val != 0,
.boolean => |b| b,
.none => false,
};
}
};
test "enums with inferred tags" {
var v = Variant{ .int = 42 };
testing.expect(Variant.truthy(v));
v = Variant.none;
testing.expect(!v.truthy());
v = Variant{ .boolean = false };
const res = switch (v) {
.int => |val| val,
.boolean => |b| @boolToInt(b),
.none => unreachable,
};
testing.expect(res == 0);
}
test "get tag name" {
const v = Variant.none;
testing.expect(mem.eql(u8, "none", @tagName(v)));
}
test "get tag type of a tagged union" {
debug.print("{}\n", .{@typeInfo(Variant).Union.tag_type});
}
fn makeBoolean(b: bool) Variant {
return .{ .boolean = b };
}
// we can use anoymous struct literals to construct union literals
test "anonymous union literals" {
const v1 = .{ .int = 42 };
debug.print("{}\n", .{v1});
const v2 = .{.none};
debug.print("{}\n", .{v2});
const v3 = makeBoolean(false);
debug.print("{}\n", .{v3});
}