enum
enums.zig
const expect = @import("std").testing.expect;
const mem = @import("std").mem;
// Declare an enum.
const Type = enum {
ok,
not_ok,
};
// 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" {
try expect(@enumToInt(Value.zero) == 0);
try expect(@enumToInt(Value.one) == 1);
try expect(@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" {
try expect(@enumToInt(Value2.hundred) == 100);
try expect(@enumToInt(Value2.thousand) == 1000);
try expect(@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;
try expect(!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",
};
try expect(mem.eql(u8, what_is_it, "this is a number"));
}
// @typeInfo can be used to access the integer tag type of an enum.
const Small = enum {
one,
two,
three,
four,
};
test "std.meta.Tag" {
try expect(@typeInfo(Small).Enum.tag_type == u2);
}
// @typeInfo tells us the field count and the fields names:
test "@typeInfo" {
try expect(@typeInfo(Small).Enum.fields.len == 4);
try expect(mem.eql(u8, @typeInfo(Small).Enum.fields[1].name, "two"));
}
// @tagName gives a []const u8 representation of an enum value:
test "@tagName" {
try expect(mem.eql(u8, @tagName(Small.three), "three"));
}
$ zig test enums.zig
Test [1/7] test "enum ordinal value"...
Test [2/7] test "set enum ordinal value"...
Test [3/7] test "enum method"...
Test [4/7] test "enum variant switch"...
Test [5/7] test "std.meta.Tag"...
Test [6/7] test "@typeInfo"...
Test [7/7] test "@tagName"...
All 7 tests passed.
See also:
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
./docgen_tmp/test.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'C'
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
Enum Literals
Enum literals allow specifying the name of an enum field without specifying the enum type:
test.zig
const std = @import("std");
const expect = std.testing.expect;
const Color = enum {
auto,
off,
on,
};
test "enum literals" {
const color1: Color = .auto;
const color2 = Color.auto;
try expect(color1 == color2);
}
test "switch using enum literals" {
const color = Color.on;
const result = switch (color) {
.auto => false,
.on => true,
.off => false,
};
try expect(result);
}
$ zig test test.zig
Test [1/2] test "enum literals"...
Test [2/2] test "switch using enum literals"...
All 2 tests passed.
Non-exhaustive enum
A Non-exhaustive enum can be created by adding a trailing ‘_‘ field. It must specify a tag type and cannot consume every enumeration value.
@intToEnum on a non-exhaustive enum cannot fail.
A switch on a non-exhaustive enum can include a ‘_‘ prong as an alternative to an else
prong with the difference being that it makes it a compile error if all the known tag names are not handled by the switch.
test.zig
const std = @import("std");
const expect = std.testing.expect;
const Number = enum(u8) {
one,
two,
three,
_,
};
test "switch on non-exhaustive enum" {
const number = Number.one;
const result = switch (number) {
.one => true,
.two,
.three => false,
_ => false,
};
try expect(result);
const is_one = switch (number) {
.one => true,
else => false,
};
try expect(is_one);
}
$ zig test test.zig
Test [1/1] test "switch on non-exhaustive enum"...
All 1 tests passed.