aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/exercises/29_errdefer.zig
diff options
context:
space:
mode:
Diffstat (limited to 'exercises/29_errdefer.zig')
-rw-r--r--exercises/29_errdefer.zig60
1 files changed, 60 insertions, 0 deletions
diff --git a/exercises/29_errdefer.zig b/exercises/29_errdefer.zig
new file mode 100644
index 0000000..cd2158d
--- /dev/null
+++ b/exercises/29_errdefer.zig
@@ -0,0 +1,60 @@
+//
+// Another common problem is a block of code that could exit in multiple
+// places due to an error - but that needs to run do something before it
+// exits (typically to clean up after itself).
+//
+// An "errdefer" is a defer that only runs if the block exits with an error:
+//
+// {
+// errdefer cleanup();
+// try canFail();
+// }
+//
+// The cleanup() function is called ONLY if the "try" statement returns an
+// error produced by canFail().
+//
+const std = @import("std");
+
+//
+var counter: u32 = 0;
+
+const MyErr = error{ GetFail, IncFail };
+
+pub fn main() void {
+ // We simply quit the entire program if we fail to get a number:
+ var a: u32 = makeNumber() catch return;
+ var b: u32 = makeNumber() catch return;
+
+ std.debug.print("Numbers: {}, {}\n", .{a,b});
+}
+
+fn makeNumber() MyErr!u32 {
+ std.debug.print("Getting number...", .{});
+
+ // Please make the "failed" message print ONLY if the makeNumber()
+ // function exits with an error:
+ std.debug.print("failed!\n", .{});
+
+ var num = try getNumber(); // <-- This could fail!
+
+ num = try increaseNumber(num); // <-- This could ALSO fail!
+
+ std.debug.print("got {}. ", .{num});
+
+ return num;
+}
+
+fn getNumber() MyErr!u32 {
+ // I _could_ fail...but I don't!
+ return 4;
+}
+
+fn increaseNumber(n: u32) MyErr!u32 {
+ // I fail after the first time you run me!
+ if (counter > 0) return MyErr.IncFail;
+
+ // Sneaky, weird global stuff.
+ counter += 1;
+
+ return n + 1;
+}