enum

enums.zig

  1. const assert = @import("std").debug.assert;
  2. const mem = @import("std").mem;
  3. // Declare an enum.
  4. const Type = enum {
  5. Ok,
  6. NotOk,
  7. };
  8. // Declare a specific instance of the enum variant.
  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 for each member.
  19. test "enum ordinal value" {
  20. assert(@enumToInt(Value.Zero) == 0);
  21. assert(@enumToInt(Value.One) == 1);
  22. assert(@enumToInt(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. assert(@enumToInt(Value2.Hundred) == 100);
  32. assert(@enumToInt(Value2.Thousand) == 1000);
  33. assert(@enumToInt(Value2.Million) == 1000000);
  34. }
  35. // Enums can have methods, the same as structs and unions.
  36. // Enum methods are not special, they are only namespaced
  37. // functions that you can call with dot syntax.
  38. const Suit = enum {
  39. Clubs,
  40. Spades,
  41. Diamonds,
  42. Hearts,
  43. pub fn isClubs(self: Suit) bool {
  44. return self == Suit.Clubs;
  45. }
  46. };
  47. test "enum method" {
  48. const p = Suit.Spades;
  49. assert(!p.isClubs());
  50. }
  51. // An enum variant of different types can be switched upon.
  52. const Foo = enum {
  53. String,
  54. Number,
  55. None,
  56. };
  57. test "enum variant switch" {
  58. const p = Foo.Number;
  59. const what_is_it = switch (p) {
  60. Foo.String => "this is a string",
  61. Foo.Number => "this is a number",
  62. Foo.None => "this is a none",
  63. };
  64. assert(mem.eql(u8, what_is_it, "this is a number"));
  65. }
  66. // @TagType can be used to access the integer tag type of an enum.
  67. const Small = enum {
  68. One,
  69. Two,
  70. Three,
  71. Four,
  72. };
  73. test "@TagType" {
  74. assert(@TagType(Small) == u2);
  75. }
  76. // @memberCount tells how many fields an enum has:
  77. test "@memberCount" {
  78. assert(@memberCount(Small) == 4);
  79. }
  80. // @memberName tells the name of a field in an enum:
  81. test "@memberName" {
  82. assert(mem.eql(u8, @memberName(Small, 1), "Two"));
  83. }
  84. // @tagName gives a []const u8 representation of an enum value:
  85. test "@tagName" {
  86. assert(mem.eql(u8, @tagName(Small.Three), "Three"));
  87. }
  1. $ zig test enums.zig
  2. 1/8 test "enum ordinal value"...OK
  3. 2/8 test "set enum ordinal value"...OK
  4. 3/8 test "enum method"...OK
  5. 4/8 test "enum variant switch"...OK
  6. 5/8 test "@TagType"...OK
  7. 6/8 test "@memberCount"...OK
  8. 7/8 test "@memberName"...OK
  9. 8/8 test "@tagName"...OK
  10. All tests passed.

See also:

extern enum

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

test.zig

  1. const Foo = enum { A, B, C };
  2. export fn entry(foo: Foo) void { }
  1. $ zig build-obj test.zig
  2. /home/andy/dev/zig/docgen_tmp/test.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'
  3. export fn entry(foo: Foo) void {
  4. ^

For a C-ABI-compatible enum, use extern enum:

test.zig

  1. const Foo = extern enum { A, B, C };
  2. export fn entry(foo: Foo) void { }
  1. $ 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

  1. const std = @import("std");
  2. test "packed enum" {
  3. const Number = packed enum(u8) {
  4. One,
  5. Two,
  6. Three,
  7. };
  8. std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
  9. }
  1. $ zig test test.zig
  2. 1/1 test "packed enum"...OK
  3. All tests passed.

This makes the enum eligible to be in a packed struct.

Enum Literals

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

test.zig

  1. const std = @import("std");
  2. const assert = std.debug.assert;
  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. assert(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. assert(result);
  21. }
  1. $ zig test test.zig
  2. 1/2 test "enum literals"...OK
  3. 2/2 test "switch using enum literals"...OK
  4. All tests passed.