defer

defer.zig

  1. const std = @import("std");
  2. const assert = std.debug.assert;
  3. const warn = std.debug.warn;
  4. // defer will execute an expression at the end of the current scope.
  5. fn deferExample() usize {
  6. var a: usize = 1;
  7. {
  8. defer a = 2;
  9. a = 1;
  10. }
  11. assert(a == 2);
  12. a = 5;
  13. return a;
  14. }
  15. test "defer basics" {
  16. assert(deferExample() == 5);
  17. }
  18. // If multiple defer statements are specified, they will be executed in
  19. // the reverse order they were run.
  20. fn deferUnwindExample() void {
  21. warn("\n");
  22. defer {
  23. warn("1 ");
  24. }
  25. defer {
  26. warn("2 ");
  27. }
  28. if (false) {
  29. // defers are not run if they are never executed.
  30. defer {
  31. warn("3 ");
  32. }
  33. }
  34. }
  35. test "defer unwinding" {
  36. deferUnwindExample();
  37. }
  38. // The errdefer keyword is similar to defer, but will only execute if the
  39. // scope returns with an error.
  40. //
  41. // This is especially useful in allowing a function to clean up properly
  42. // on error, and replaces goto error handling tactics as seen in c.
  43. fn deferErrorExample(is_error: bool) !void {
  44. warn("\nstart of function\n");
  45. // This will always be executed on exit
  46. defer {
  47. warn("end of function\n");
  48. }
  49. errdefer {
  50. warn("encountered an error!\n");
  51. }
  52. if (is_error) {
  53. return error.DeferError;
  54. }
  55. }
  56. test "errdefer unwinding" {
  57. deferErrorExample(false) catch {};
  58. deferErrorExample(true) catch {};
  59. }
  1. $ zig test defer.zig
  2. 1/3 test "defer basics"...OK
  3. 2/3 test "defer unwinding"...
  4. 2 1 OK
  5. 3/3 test "errdefer unwinding"...
  6. start of function
  7. end of function
  8. start of function
  9. encountered an error!
  10. end of function
  11. OK
  12. All tests passed.

See also: