유효하지 않은 에러 코드

유효하지 않은 에러 코드

어떤 정수 값을 에러로 바꾸려고 할 때, 그 값이 실제로 어떤 에러도 나타내지 않는다면 컴파일 타임과 런타임에서 각각 다른 방식으로 실패하게 돼요. 이 섹션에서는 @errorFromInt가 이런 상황에서 어떻게 동작하는지 두 경우로 나눠 살펴볼게요.

출처: Zig Documentation

본문

컴파일 타임에는 이렇게 써볼 수 있어요. @errorFromInt에 에러를 표현하지 않는 정수를 넘기면 컴파일러가 바로 잡아내죠.

comptime {
    _ = @errorFromInt(12345);
}
$ zig test test_comptime_invalid_error_code.zig
/home/ci/work/zig-bootstrap/zig/doc/langref/test_comptime_invalid_error_code.zig:2:23: error: integer value '12345' represents no error
    _ = @errorFromInt(12345);
                      ^~~~~

12345는 어떤 에러 값에도 해당하지 않아요. 그래서 이건 no error를 의미하는 정수라는 에러 메시지가 나오면서 컴파일이 실패하는 걸 볼 수 있어요.

런타임에는 값을 예측할 수 없을 때가 있죠. 아래처럼 에러에서 정수로 바꾼 뒤 500을 더해, 실제로 존재하지 않는 에러 코드를 만들어볼게요.

const std = @import("std");

pub fn main() void {
    const err = error.AnError;
    var number = @intFromError(err) + 500;
    _ = &number;
    const invalid_err = @errorFromInt(number);
    std.debug.print("value: {}\n", .{invalid_err});
}
$ zig build-exe runtime_invalid_error_code.zig
$ ./runtime_invalid_error_code
thread 972966 panic: invalid error code
/home/ci/work/zig-bootstrap/zig/doc/langref/runtime_invalid_error_code.zig:7:5: 0x11e82c5 in main (runtime_invalid_error_code.zig)
    const invalid_err = @errorFromInt(number);
    ^
/home/ci/work/zig-bootstrap/out/host/lib/zig/std/start.zig:788:64: 0x11e7bbb in callMain (std.zig)
    if (fn_info.param_types.len == 0) return wrapMain(root.main());
                                                               ^
/home/ci/work/zig-bootstrap/out/host/lib/zig/std/start.zig:248:5: 0x11e75e1 in _start (std.zig)
    asm volatile (switch (native_arch) {
    ^
(process terminated by signal)

이번에는 컴파일러가 잡아주지 않아요. number가 런타임에 계산되는 값이라 컴파일러가 미리 알 수 없거든요. 실행하면 panic: invalid error code가 나오면서 프로그램이 죽는 걸 확인할 수 있어요.

더 알아보기

  • @errorFromInt / @intFromError — 정수와 에러 값을 서로 변환하는 내장 함수
  • 에러 값과 에러 유니온의 전반적인 동작은 Zig 문서의 Errors 섹션에서 다뤄져요.