switch

switch.zig

  1. const std = @import("std");
  2. const builtin = @import("builtin");
  3. const expect = std.testing.expect;
  4. test "switch simple" {
  5. const a: u64 = 10;
  6. const zz: u64 = 103;
  7. // All branches of a switch expression must be able to be coerced to a
  8. // common type.
  9. //
  10. // Branches cannot fallthrough. If fallthrough behavior is desired, combine
  11. // the cases and use an if.
  12. const b = switch (a) {
  13. // Multiple cases can be combined via a ','
  14. 1, 2, 3 => 0,
  15. // Ranges can be specified using the ... syntax. These are inclusive
  16. // both ends.
  17. 5...100 => 1,
  18. // Branches can be arbitrarily complex.
  19. 101 => blk: {
  20. const c: u64 = 5;
  21. break :blk c * 2 + 1;
  22. },
  23. // Switching on arbitrary expressions is allowed as long as the
  24. // expression is known at compile-time.
  25. zz => zz,
  26. blk: {
  27. const d: u32 = 5;
  28. const e: u32 = 100;
  29. break :blk d + e;
  30. } => 107,
  31. // The else branch catches everything not already captured.
  32. // Else branches are mandatory unless the entire range of values
  33. // is handled.
  34. else => 9,
  35. };
  36. try expect(b == 1);
  37. }
  38. // Switch expressions can be used outside a function:
  39. const os_msg = switch (builtin.target.os.tag) {
  40. .linux => "we found a linux user",
  41. else => "not a linux user",
  42. };
  43. // Inside a function, switch statements implicitly are compile-time
  44. // evaluated if the target expression is compile-time known.
  45. test "switch inside function" {
  46. switch (builtin.target.os.tag) {
  47. .fuchsia => {
  48. // On an OS other than fuchsia, block is not even analyzed,
  49. // so this compile error is not triggered.
  50. // On fuchsia this compile error would be triggered.
  51. @compileError("fuchsia not supported");
  52. },
  53. else => {},
  54. }
  55. }

Shell

  1. $ zig test switch.zig
  2. 1/2 test "switch simple"... OK
  3. 2/2 test "switch inside function"... OK
  4. All 2 tests passed.

switch can be used to capture the field values of a Tagged union. Modifications to the field values can be done by placing a * before the capture variable name, turning it into a pointer.

test_switch_tagged_union.zig

  1. const expect = @import("std").testing.expect;
  2. test "switch on tagged union" {
  3. const Point = struct {
  4. x: u8,
  5. y: u8,
  6. };
  7. const Item = union(enum) {
  8. a: u32,
  9. c: Point,
  10. d,
  11. e: u32,
  12. };
  13. var a = Item{ .c = Point{ .x = 1, .y = 2 } };
  14. // Switching on more complex enums is allowed.
  15. const b = switch (a) {
  16. // A capture group is allowed on a match, and will return the enum
  17. // value matched. If the payload types of both cases are the same
  18. // they can be put into the same switch prong.
  19. Item.a, Item.e => |item| item,
  20. // A reference to the matched value can be obtained using `*` syntax.
  21. Item.c => |*item| blk: {
  22. item.*.x += 1;
  23. break :blk 6;
  24. },
  25. // No else is required if the types cases was exhaustively handled
  26. Item.d => 8,
  27. };
  28. try expect(b == 6);
  29. try expect(a.c.x == 2);
  30. }

Shell

  1. $ zig test test_switch_tagged_union.zig
  2. 1/1 test "switch on tagged union"... OK
  3. All 1 tests passed.

See also:

Exhaustive Switching

When a switch expression does not have an else clause, it must exhaustively list all the possible values. Failure to do so is a compile error:

test.zig

  1. const Color = enum {
  2. auto,
  3. off,
  4. on,
  5. };
  6. test "exhaustive switching" {
  7. const color = Color.off;
  8. switch (color) {
  9. Color.auto => {},
  10. Color.on => {},
  11. }
  12. }

Shell

  1. $ zig test test.zig
  2. ./docgen_tmp/test.zig:9:5: error: enumeration value 'Color.off' not handled in switch
  3. switch (color) {
  4. ^
  5. ./docgen_tmp/test.zig:7:29: note: referenced here
  6. test "exhaustive switching" {
  7. ^

Switching with Enum Literals

Enum Literals can be useful to use with switch to avoid repetitively specifying enum or union types:

test_exhaustive_switch.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 with switch" {
  9. const color = Color.off;
  10. const result = switch (color) {
  11. .auto => false,
  12. .on => false,
  13. .off => true,
  14. };
  15. try expect(result);
  16. }

Shell

  1. $ zig test test_exhaustive_switch.zig
  2. 1/1 test "enum literals with switch"... OK
  3. All 1 tests passed.