enum
enums.zig
const assert = @import("std").debug.assert;
const mem = @import("std").mem;
// Declare an enum.
const Type = enum {
Ok,
NotOk,
};
// Declare a specific instance of the enum variant.
const c = Type.Ok;
// If you want access to the ordinal value of an enum, you
// can specify the tag type.
const Value = enum(u2) {
Zero,
One,
Two,
};
// Now you can cast between u2 and Value.
// The ordinal value starts from 0, counting up for each member.
test "enum ordinal value" {
assert(@enumToInt(Value.Zero) == 0);
assert(@enumToInt(Value.One) == 1);
assert(@enumToInt(Value.Two) == 2);
}
// You can override the ordinal value for an enum.
const Value2 = enum(u32) {
Hundred = 100,
Thousand = 1000,
Million = 1000000,
};
test "set enum ordinal value" {
assert(@enumToInt(Value2.Hundred) == 100);
assert(@enumToInt(Value2.Thousand) == 1000);
assert(@enumToInt(Value2.Million) == 1000000);
}
// Enums can have methods, the same as structs and unions.
// Enum methods are not special, they are only namespaced
// functions that you can call with dot syntax.
const Suit = enum {
Clubs,
Spades,
Diamonds,
Hearts,
pub fn isClubs(self: Suit) bool {
return self == Suit.Clubs;
}
};
test "enum method" {
const p = Suit.Spades;
assert(!p.isClubs());
}
// An enum variant of different types can be switched upon.
const Foo = enum {
String,
Number,
None,
};
test "enum variant switch" {
const p = Foo.Number;
const what_is_it = switch (p) {
Foo.String => "this is a string",
Foo.Number => "this is a number",
Foo.None => "this is a none",
};
assert(mem.eql(u8, what_is_it, "this is a number"));
}
// @TagType can be used to access the integer tag type of an enum.
const Small = enum {
One,
Two,
Three,
Four,
};
test "@TagType" {
assert(@TagType(Small) == u2);
}
// @memberCount tells how many fields an enum has:
test "@memberCount" {
assert(@memberCount(Small) == 4);
}
// @memberName tells the name of a field in an enum:
test "@memberName" {
assert(mem.eql(u8, @memberName(Small, 1), "Two"));
}
// @tagName gives a []const u8 representation of an enum value:
test "@tagName" {
assert(mem.eql(u8, @tagName(Small.Three), "Three"));
}
$ zig test enums.zig
Test 1/8 enum ordinal value...OK
Test 2/8 set enum ordinal value...OK
Test 3/8 enum method...OK
Test 4/8 enum variant switch...OK
Test 5/8 @TagType...OK
Test 6/8 @memberCount...OK
Test 7/8 @memberName...OK
Test 8/8 @tagName...OK
All tests passed.
extern enum
By default, enums are not guaranteed to be compatible with the C ABI:
test.zig
const Foo = enum { A, B, C };
export fn entry(foo: Foo) void { }
$ zig build-obj test.zig
/home/andy/dev/zig/docgen_tmp/test.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'
export fn entry(foo: Foo) void {
^
For a C-ABI-compatible enum, use extern enum
:
test.zig
const Foo = extern enum { A, B, C };
export fn entry(foo: Foo) void { }
$ zig build-obj test.zig
packed enum
By default, the size of enums is not guaranteed.
packed enum
causes the size of the enum to be the same as the size of the integer tag type of the enum:
test.zig
const std = @import("std");
test "packed enum" {
const Number = packed enum(u8) {
One,
Two,
Three,
};
std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
}
$ zig test test.zig
Test 1/1 packed enum...OK
All tests passed.
This makes the enum eligible to be in a packed struct.
See also: