029_errdefer.zig 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. //
  2. // Another common problem is a block of code that could exit in multiple
  3. // places due to an error - but that needs to run do something before it
  4. // exits (typically to clean up after itself).
  5. //
  6. // An "errdefer" is a defer that only runs if the block exits with an error:
  7. //
  8. // {
  9. // errdefer cleanup();
  10. // try canFail();
  11. // }
  12. //
  13. // The cleanup() function is called ONLY if the "try" statement returns an
  14. // error produced by canFail().
  15. //
  16. const std = @import("std");
  17. var counter: u32 = 0;
  18. const MyErr = error{ GetFail, IncFail };
  19. pub fn main() void {
  20. // We simply quit the entire program if we fail to get a number:
  21. var a: u32 = makeNumber() catch return;
  22. var b: u32 = makeNumber() catch return;
  23. std.debug.print("Numbers: {}, {}\n", .{ a, b });
  24. }
  25. fn makeNumber() MyErr!u32 {
  26. std.debug.print("Getting number...", .{});
  27. // Please make the "failed" message print ONLY if the makeNumber()
  28. // function exits with an error:
  29. std.debug.print("failed!\n", .{});
  30. var num = try getNumber(); // <-- This could fail!
  31. num = try increaseNumber(num); // <-- This could ALSO fail!
  32. std.debug.print("got {}. ", .{num});
  33. return num;
  34. }
  35. fn getNumber() MyErr!u32 {
  36. // I _could_ fail...but I don't!
  37. return 4;
  38. }
  39. fn increaseNumber(n: u32) MyErr!u32 {
  40. // I fail after the first time you run me!
  41. if (counter > 0) return MyErr.IncFail;
  42. // Sneaky, weird global stuff.
  43. counter += 1;
  44. return n + 1;
  45. }