enum

test_enums.zig

  1. const expect = @import("std").testing.expect;
  2. const mem = @import("std").mem;
  3. // Declare an enum.
  4. const Type = enum {
  5. ok,
  6. not_ok,
  7. };
  8. // Declare a specific enum field.
  9. const c = Type.ok;
  10. // If you want access to the ordinal value of an enum, you
  11. // can specify the tag type.
  12. const Value = enum(u2) {
  13. zero,
  14. one,
  15. two,
  16. };
  17. // Now you can cast between u2 and Value.
  18. // The ordinal value starts from 0, counting up by 1 from the previous member.
  19. test "enum ordinal value" {
  20. try expect(@intFromEnum(Value.zero) == 0);
  21. try expect(@intFromEnum(Value.one) == 1);
  22. try expect(@intFromEnum(Value.two) == 2);
  23. }
  24. // You can override the ordinal value for an enum.
  25. const Value2 = enum(u32) {
  26. hundred = 100,
  27. thousand = 1000,
  28. million = 1000000,
  29. };
  30. test "set enum ordinal value" {
  31. try expect(@intFromEnum(Value2.hundred) == 100);
  32. try expect(@intFromEnum(Value2.thousand) == 1000);
  33. try expect(@intFromEnum(Value2.million) == 1000000);
  34. }
  35. // You can also override only some values.
  36. const Value3 = enum(u4) {
  37. a,
  38. b = 8,
  39. c,
  40. d = 4,
  41. e,
  42. };
  43. test "enum implicit ordinal values and overridden values" {
  44. try expect(@intFromEnum(Value3.a) == 0);
  45. try expect(@intFromEnum(Value3.b) == 8);
  46. try expect(@intFromEnum(Value3.c) == 9);
  47. try expect(@intFromEnum(Value3.d) == 4);
  48. try expect(@intFromEnum(Value3.e) == 5);
  49. }
  50. // Enums can have methods, the same as structs and unions.
  51. // Enum methods are not special, they are only namespaced
  52. // functions that you can call with dot syntax.
  53. const Suit = enum {
  54. clubs,
  55. spades,
  56. diamonds,
  57. hearts,
  58. pub fn isClubs(self: Suit) bool {
  59. return self == Suit.clubs;
  60. }
  61. };
  62. test "enum method" {
  63. const p = Suit.spades;
  64. try expect(!p.isClubs());
  65. }
  66. // An enum can be switched upon.
  67. const Foo = enum {
  68. string,
  69. number,
  70. none,
  71. };
  72. test "enum switch" {
  73. const p = Foo.number;
  74. const what_is_it = switch (p) {
  75. Foo.string => "this is a string",
  76. Foo.number => "this is a number",
  77. Foo.none => "this is a none",
  78. };
  79. try expect(mem.eql(u8, what_is_it, "this is a number"));
  80. }
  81. // @typeInfo can be used to access the integer tag type of an enum.
  82. const Small = enum {
  83. one,
  84. two,
  85. three,
  86. four,
  87. };
  88. test "std.meta.Tag" {
  89. try expect(@typeInfo(Small).Enum.tag_type == u2);
  90. }
  91. // @typeInfo tells us the field count and the fields names:
  92. test "@typeInfo" {
  93. try expect(@typeInfo(Small).Enum.fields.len == 4);
  94. try expect(mem.eql(u8, @typeInfo(Small).Enum.fields[1].name, "two"));
  95. }
  96. // @tagName gives a [:0]const u8 representation of an enum value:
  97. test "@tagName" {
  98. try expect(mem.eql(u8, @tagName(Small.three), "three"));
  99. }

Shell

  1. $ zig test test_enums.zig
  2. 1/8 test_enums.test.enum ordinal value... OK
  3. 2/8 test_enums.test.set enum ordinal value... OK
  4. 3/8 test_enums.test.enum implicit ordinal values and overridden values... OK
  5. 4/8 test_enums.test.enum method... OK
  6. 5/8 test_enums.test.enum switch... OK
  7. 6/8 test_enums.test.std.meta.Tag... OK
  8. 7/8 test_enums.test.@typeInfo... OK
  9. 8/8 test_enums.test.@tagName... OK
  10. All 8 tests passed.

See also:

extern enum

By default, enums are not guaranteed to be compatible with the C ABI:

enum_export_error.zig

  1. const Foo = enum { a, b, c };
  2. export fn entry(foo: Foo) void { _ = foo; }

Shell

  1. $ zig build-obj enum_export_error.zig
  2. docgen_tmp/enum_export_error.zig:2:17: error: parameter of type 'enum_export_error.Foo' not allowed in function with calling convention 'C'
  3. export fn entry(foo: Foo) void { _ = foo; }
  4. ^~~~~~~~
  5. docgen_tmp/enum_export_error.zig:2:17: note: enum tag type 'u2' is not extern compatible
  6. docgen_tmp/enum_export_error.zig:2:17: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
  7. docgen_tmp/enum_export_error.zig:1:13: note: enum declared here
  8. const Foo = enum { a, b, c };
  9. ^~~~~~~~~~~~~~~~

For a C-ABI-compatible enum, provide an explicit tag type to the enum:

enum_export.zig

  1. const Foo = enum(c_int) { a, b, c };
  2. export fn entry(foo: Foo) void { _ = foo; }

Shell

  1. $ zig build-obj enum_export.zig

Enum Literals

Enum literals allow specifying the name of an enum field without specifying the enum type:

test_enum_literals.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. const Color = enum {
  4. auto,
  5. off,
  6. on,
  7. };
  8. test "enum literals" {
  9. const color1: Color = .auto;
  10. const color2 = Color.auto;
  11. try expect(color1 == color2);
  12. }
  13. test "switch using enum literals" {
  14. const color = Color.on;
  15. const result = switch (color) {
  16. .auto => false,
  17. .on => true,
  18. .off => false,
  19. };
  20. try expect(result);
  21. }

Shell

  1. $ zig test test_enum_literals.zig
  2. 1/2 test_enum_literals.test.enum literals... OK
  3. 2/2 test_enum_literals.test.switch using enum literals... OK
  4. All 2 tests passed.

Non-exhaustive enum

A non-exhaustive enum can be created by adding a trailing _ field. The enum must specify a tag type and cannot consume every enumeration value.

@enumFromInt on a non-exhaustive enum involves the safety semantics of @intCast to the integer tag type, but beyond that always results in a well-defined enum value.

A switch on a non-exhaustive enum can include a _ prong as an alternative to an else prong. With a _ prong the compiler errors if all the known tag names are not handled by the switch.

test_switch_non-exhaustive.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. const Number = enum(u8) {
  4. one,
  5. two,
  6. three,
  7. _,
  8. };
  9. test "switch on non-exhaustive enum" {
  10. const number = Number.one;
  11. const result = switch (number) {
  12. .one => true,
  13. .two,
  14. .three => false,
  15. _ => false,
  16. };
  17. try expect(result);
  18. const is_one = switch (number) {
  19. .one => true,
  20. else => false,
  21. };
  22. try expect(is_one);
  23. }

Shell

  1. $ zig test test_switch_non-exhaustive.zig
  2. 1/1 test_switch_non-exhaustive.test.switch on non-exhaustive enum... OK
  3. All 1 tests passed.