Error Union em Zig — O que é e Como Usar
Definição
Um Error Union em Zig é um tipo composto representado pelo operador ! que pode conter ou um valor válido ou um erro. É o mecanismo fundamental de tratamento de erros da linguagem, substituindo exceções (como em Java/Python) e códigos de retorno (como em C).
A sintaxe ErrorSet!T significa “este valor é do tipo T ou é um erro do conjunto ErrorSet”. Quando o error set é omitido (!T), o compilador infere o conjunto de erros automaticamente.
Por que Error Unions Importam
- Erros são valores: Em Zig, erros são cidadãos de primeira classe no sistema de tipos — não são exceções invisíveis.
- Impossível ignorar erros: O compilador obriga você a lidar com o caso de erro explicitamente.
- Zero custo: Error unions são implementados de forma eficiente, sem overhead de exceções.
- Composição: Funções que retornam error unions se compõem naturalmente com
try.
Exemplo Prático
Retornando Error Unions
const std = @import("std");
const MathError = error{
DivisaoPorZero,
Overflow,
};
fn dividir(a: i32, b: i32) MathError!i32 {
if (b == 0) return MathError.DivisaoPorZero;
return @divTrunc(a, b);
}
pub fn main() void {
// Tratando o erro explicitamente
const resultado = dividir(10, 3) catch |err| {
std.debug.print("Erro: {}\n", .{err});
return;
};
std.debug.print("10 / 3 = {}\n", .{resultado});
}
Usando com try
fn processarDados() !void {
const valor = try dividir(100, 5); // Propaga erro automaticamente
std.debug.print("Resultado: {}\n", .{valor});
}
try é equivalente a:
const valor = dividir(100, 5) catch |err| return err;
Usando com if
fn exemploIf() void {
if (dividir(10, 0)) |valor| {
std.debug.print("Sucesso: {}\n", .{valor});
} else |err| {
std.debug.print("Erro: {}\n", .{err});
}
}
Error Union com tipo inferido
// O compilador infere o error set automaticamente
fn lerArquivo(caminho: []const u8) ![]const u8 {
const arquivo = try std.fs.cwd().openFile(caminho, .{});
defer arquivo.close();
return try arquivo.readToEndAlloc(std.heap.page_allocator, 1024 * 1024);
}
Anatomia do Tipo
ErrorSet ! PayloadType
│ │
│ └── Tipo do valor em caso de sucesso
└── Conjunto de possíveis erros
Exemplos:
error{OutOfMemory}![]u8 — Pode ser OutOfMemory ou um slice de bytes
anyerror!void — Qualquer erro ou void (sem valor)
!u32 — Error set inferido, valor u32
Armadilhas Comuns
- Usar
anyerrordesnecessariamente: Prefira error sets específicos.anyerrordesabilita otimizações do compilador e dificulta a documentação da API. - Ignorar erros com
catch unreachable: Só use quando tiver certeza absoluta de que o erro não pode ocorrer. Caso contrário, isso causará um panic em runtime. - Confundir
!Tcom?T: Error union (!T) carrega informação de erro; optional (?T) apenas indica presença/ausência de valor. - Não propagar erros: Se sua função não sabe lidar com o erro, propague-o com
tryem vez de engolir silenciosamente.
Termos Relacionados
- Error Set — Conjuntos de erros nomeados
- Try — Operador de propagação de erros
- Catch — Operador para capturar erros
- Optional — Tipo que pode ser null
- Errdefer — Defer condicional para erros