Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Fundamental

Error Handling

In Zig, errors are represented as values, and is supported with native language features.

// define an error set
const NumberError = error{
    TooBig,
    TooSmall,
};

// failable function, returns an error union
// on error, it's `NumberError` variant
// on success, it's `i32` variant
fn failable() NumberError!i32 {
    if (number > 100) {
        return NumberError.TooBig; // specify error type
    } else if (number < 0) {
        return error.TooSmall;     // infer error type
    }
    return number;
}

// ignore error with default value
const fallback = failable() catch 50; // on error, fallback to 50

// handle error
const handle = failable() catch |err| {
    switch (err) {
        NumberError.TooBig => std.debug.print("Number is too big!\n", .{}),
        NumberError.TooSmall => std.debug.print("Number is too small!\n", .{}),
    }
};

// propagate error
fn anyhow() NumberError!void {
  const res = try failable();  // early return on error
}

// handle error with `if-else` & `switch`
const res = failable();
if (res) |val| { // <~ if success, `val` is the value
    std.debug.print("Value: {}\n", .{val});
} else |err| switch (err) { // <~ if error, `err` is the error. switch is not required
    NumberError.TooBig => std.debug.print("Number is too big!\n", .{}),
    NumberError.TooSmall => std.debug.print("Number is too small!\n", .{}),
}

Defer Execution

The defer keyword can be used to schedule a function to be executed when the current scope exits. The errdefer keyword can be used to schedule a function to be executed when the scope exits with an error.

// When a function may return in many places, `defer` can be used to ensure
// that a "tail" function is called at the end of the function, regardless of how
// the function exits.
fn printClosedWord(cond: bool) void {
    std.debug.print("(", .{});

    defer std.debug.print(") ", .{}); // <~ deferred

    if (cond) {
        std.debug.print("True", .{});
        return;
    } else {
        std.debug.print("False", .{});
        return;
    }
}

// When a function may early return with an error, `errdefer` can be used to
// ensure that a "error tail" function is called when the function exits with an
// error.
fn example() !void {
    errdefer std.debug.print("failed!\n", .{}); // <~ deferred (on error)
    const res = try failable(); // <~ possible early return
}