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
- Documentação no tipo: A assinatura da função declara exatamente quais erros pode produzir.
- Exaustividade: O compilador pode verificar se todos os casos de erro foram tratados em um
switch. - Composição: Error sets podem ser unidos com o operador
||, combinando erros de diferentes fontes. - 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
anyerrorem 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,@errorNamee 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