029_errdefer.zig 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  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 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. const a: u32 = makeNumber() catch return;
  22. const 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. errdefer 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. }