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. try expect(a == 2);
  12. a = 5;
  13. return a;
  14. }
  15. test "defer basics" {
  16. try expect((try 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. // inside a defer method the return statement
  53. // is not allowed.
  54. // The following lines produce the following
  55. // error if uncomment
  56. //
  1. // defer.zig:73:9: error: cannot return from defer expression
  2. // return error.DeferError;
  3. // ```
  4. //
  5. //defer {
  6. // return error.DeferError;
  7. //}
  8. if (is_error) {
  9. return error.DeferError;
  10. }

}

// The errdefer keyword support also an alternative syntax to capture the // error generated in case of one error. // // This is useful when during the clean up after an error additional // message want to be printed. fn deferErrorCaptureExample() !void { errdefer |err| { std.debug.print(“the error is {s}\n”, .{@errorName(err)}); }

  1. return error.DeferError;

}

test “errdefer unwinding” { deferErrorExample(false) catch {}; deferErrorExample(true) catch {}; deferErrorCaptureExample() catch {}; }

  1. Shell

$ zig test defer.zig 1/3 test.defer basics… OK 2/3 test.defer unwinding… 2 1 OK 3/3 test.errdefer unwinding… start of function end of function

start of function encountered an error! end of function the error is DeferError OK All 3 tests passed. ```

See also: