Error Set em Zig — O que é e Como Usar

Error Set em Zig — O que é e Como Usar

Definição

Um Error Set em Zig é um tipo que define um conjunto finito de erros nomeados que uma função pode retornar. É a parte “erro” de um Error Union. Error sets permitem que o sistema de tipos rastreie exatamente quais erros podem ocorrer em cada ponto do programa.

Error sets são representados internamente como inteiros, tornando-os extremamente eficientes — comparáveis a enums em termos de performance.

Por que Error Sets Importam

  1. Documentação no tipo: A assinatura da função declara exatamente quais erros pode produzir.
  2. Exaustividade: O compilador pode verificar se todos os casos de erro foram tratados em um switch.
  3. Composição: Error sets podem ser unidos com o operador ||, combinando erros de diferentes fontes.
  4. Eficiência: Representados como inteiros compactos, sem alocação.

Exemplo Prático

Declarando um Error Set

const ArquivoError = error{
    ArquivoNaoEncontrado,
    PermissaoNegada,
    DiskCheio,
};

fn abrirConfiguracao() ArquivoError![]const u8 {
    // Pode retornar qualquer erro do ArquivoError
    return ArquivoError.ArquivoNaoEncontrado;
}

Combinando Error Sets

const IoError = error{
    Timeout,
    ConexaoRecusada,
};

const AppError = error{
    ConfigInvalida,
    VersaoIncompativel,
};

// União de error sets
const TodosOsErros = IoError || AppError;

fn inicializar() TodosOsErros!void {
    // Pode retornar erros de ambos os conjuntos
}

Switch Exaustivo em Erros

const std = @import("std");

const ParseError = error{
    CaractereInvalido,
    FormatoIncorreto,
    NumeroGrande,
};

fn parsear(input: []const u8) ParseError!u32 {
    _ = input;
    return ParseError.FormatoIncorreto;
}

pub fn main() void {
    const resultado = parsear("abc");
    if (resultado) |valor| {
        std.debug.print("Valor: {}\n", .{valor});
    } else |err| switch (err) {
        ParseError.CaractereInvalido => std.debug.print("Caractere inválido\n", .{}),
        ParseError.FormatoIncorreto => std.debug.print("Formato incorreto\n", .{}),
        ParseError.NumeroGrande => std.debug.print("Número grande demais\n", .{}),
    }
}

Error Set Inferido

Quando você omite o error set, o compilador o infere automaticamente:

// O compilador calcula todos os erros possíveis
fn processar() !void {
    try etapa1();  // Erros de etapa1
    try etapa2();  // + Erros de etapa2
    try etapa3();  // + Erros de etapa3
    // Error set final = união de todos
}

anyerror

O tipo anyerror é o superconjunto de todos os error sets. Qualquer erro pode ser convertido para anyerror:

fn logErro(err: anyerror) void {
    std.debug.print("Erro: {s}\n", .{@errorName(err)});
}

Armadilhas Comuns

  • Usar anyerror em APIs públicas: Perde-se a documentação de quais erros são possíveis. Prefira error sets explícitos.
  • Error sets muito grandes: Se sua função pode retornar dezenas de erros diferentes, talvez seja hora de refatorar.
  • Esquecer que error sets são tipos: Você pode usar @TypeOf, @errorName e outras built-ins para introspecção.
  • Confundir com enums: Error sets parecem enums, mas são um sistema à parte com semântica específica.

Termos Relacionados

  • Error Union — Tipo que combina error set com payload
  • Try — Propagação automática de erros
  • Catch — Captura e tratamento de erros
  • Errdefer — Limpeza condicional em caso de erro

Tutoriais Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.