defer

defer.zig

  1. const std = @import("std");
  2. const expect = std.testing.expect;
  3. const print = std.debug.print;
  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. expect(a == 2);
  12. a = 5;
  13. return a;
  14. }
  15. test "defer basics" {
  16. expect(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. print("\n", .{});
  22. defer {
  23. print("1 ", .{});
  24. }
  25. defer {
  26. print("2 ", .{});
  27. }
  28. if (false) {
  29. // defers are not run if they are never executed.
  30. defer {
  31. print("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. print("\nstart of function\n", .{});
  45. // This will always be executed on exit
  46. defer {
  47. print("end of function\n", .{});
  48. }
  49. errdefer {
  50. print("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 3 tests passed.

See also: