defer

test_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. }

Shell

  1. $ zig test test_defer.zig
  2. 1/2 test.defer basics... OK
  3. 2/2 test.defer unwinding...
  4. 2 1 OK
  5. All 2 tests passed.

test_invalid_defer.zig

  1. // Inside a defer expression the return statement is not allowed.
  2. fn deferInvalidExample() !void {
  3. defer {
  4. return error.DeferError;
  5. }
  6. return error.DeferError;
  7. }

Shell

  1. $ zig test test_invalid_defer.zig
  2. docgen_tmp/test_invalid_defer.zig:4:9: error: cannot return from defer expression
  3. return error.DeferError;
  4. ^~~~~~~~~~~~~~~~~~~~~~~
  5. docgen_tmp/test_invalid_defer.zig:3:5: note: defer expression here
  6. defer {
  7. ^~~~~

test_errdefer.zig

  1. const std = @import("std");
  2. const print = std.debug.print;
  3. // The errdefer keyword is similar to defer, but will only execute if the
  4. // scope returns with an error.
  5. //
  6. // This is especially useful in allowing a function to clean up properly
  7. // on error, and replaces goto error handling tactics as seen in c.
  8. fn deferErrorExample(is_error: bool) !void {
  9. print("\nstart of function\n", .{});
  10. // This will always be executed on exit
  11. defer {
  12. print("end of function\n", .{});
  13. }
  14. errdefer {
  15. print("encountered an error!\n", .{});
  16. }
  17. if (is_error) {
  18. return error.DeferError;
  19. }
  20. }
  21. // The errdefer keyword also supports an alternative syntax to capture the
  22. // generated error.
  23. //
  24. // This is useful for printing an additional error message during clean up.
  25. fn deferErrorCaptureExample() !void {
  26. errdefer |err| {
  27. std.debug.print("the error is {s}\n", .{@errorName(err)});
  28. }
  29. return error.DeferError;
  30. }
  31. test "errdefer unwinding" {
  32. deferErrorExample(false) catch {};
  33. deferErrorExample(true) catch {};
  34. deferErrorCaptureExample() catch {};
  35. }

Shell

  1. $ zig test test_errdefer.zig
  2. 1/1 test.errdefer unwinding...
  3. start of function
  4. end of function
  5. start of function
  6. encountered an error!
  7. end of function
  8. the error is DeferError
  9. OK
  10. All 1 tests passed.

See also: