Functions that return errors
Since errors in Zig are values, functions can return errors.
As we saw in Chapter 6, when we declare errors, we are actually giving names to a specific set of possible errors.
|
// error type for the tower const Failure = error{ Leak, Ungreased, Obstruction }; |
This allows us to write functions that can return either a valid result or one of those errors using the syntax:
- !T or
- error{...}!T
- ErrorName!T
|
fn has_failure(self: *const HTower) error{ Leak, Ungreased, Obstruction }!bool |
or like this:
|
fn has_failure(self: *const HTower) !bool |
or also like this:
|
fn has_failure(self: *const HTower) Failure!bool |
Once finished, Manitas would spend long hours inspecting the towers. He detected and sealed leaks, greased the parts, and cleaned lime and other impurities that clogged the buckets and mechanisms. If repairs had not been made, the errors would have accumulated over time, eventually ruining the tower completely.
sys_errors.zig |
|
const std = @import("std"); const print = std.debug.print; // error type const Failure = error{ Leak, Ungreased, Obstruction }; // tower from the failure point of view const HTower = struct { a_failures: std.ArrayList(Failure), fn check_tower(self: *const HTower) bool { return self.a_failures.items.len == 0; } // pure function fn has_failure(a_failures_items: []const Failure, err_x: Failure) Failure!bool { for (a_failures_items) |err_fail| if (err_fail == err_x) return err_fail; return false; } fn get_random_err() Failure { return switch (std.crypto.random.intRangeAtMost(u2, 0, 2)) { 0 => Failure.Leak, 1 => Failure.Ungreased, 2 => Failure.Obstruction, else => undefined, }; } // failure simulator - method with side effects on the property fn create_failure(self: *HTower, o_alloc: std.mem.Allocator) !void { const err_fail: Failure = get_random_err(); if (has_failure(self.a_failures.items, err_fail)) |_| try self.a_failures.append( o_alloc, err_fail, ) else |err_x| print("Failure already present {}\n", .{err_x}); } }; inline fn get_current_time_ns() i128 { return std.time.nanoTimestamp(); } const N_TOWERS = 20; const N_DELAY = 3_000_000_000; // every 3 hours (segundos) // main can return void or a failure pub fn main() !void { const o_alloc = std.heap.page_allocator; var a_towers = try std.ArrayList(HTower).initCapacity(o_alloc, N_TOWERS); for (0..N_TOWERS) |_| { try a_towers.append(o_alloc, HTower{ .a_failures = std.ArrayList(Failure).empty, }); } // time var n_time = get_current_time_ns(); while (true) { // check every N_DELAY nanoseconds if (get_current_time_ns() > (n_time + N_DELAY)) { n_time = get_current_time_ns(); // some random failures occur for (a_towers.items) |*o_tower| { if (std.crypto.random.intRangeAtMost(u8, 0, 10) >= 9) { try o_tower.create_failure(o_alloc); } } // list all errors for (a_towers.items, 0..) |o_tower, n_i| if (!o_tower.check_tower()) print( "tower {}: {any}\n", .{ n_i + 1, o_tower.a_failures.items }, ); print("\n---------------------------------\n", .{}); } } } |
|
~$ zig run sys_errors.zig |
|
tower 6: { error.Obstruction } tower 7: { error.Leak } tower 8: { error.Leak } tower 18: { error.Ungreased } tower 20: { error.Ungreased } --------------------------------- |