---
title: "Tratamento de Erros em Zig: Guia Completo"
url: "https://ziglang.com.br/tutoriais/tratamento-de-erros-em-zig/"
markdown_url: "https://ziglang.com.br/tutoriais/tratamento-de-erros-em-zig.MD"
description: "Aprenda tudo sobre o sistema de erros em Zig. Guia completo de error sets, error unions, try/catch/orelse, errdefer e melhores práticas. Domine o tratamento de erros idiomático em Zig."
date: "2026-02-10"
author: ""
---

# Tratamento de Erros em Zig: Guia Completo

Aprenda tudo sobre o sistema de erros em Zig. Guia completo de error sets, error unions, try/catch/orelse, errdefer e melhores práticas. Domine o tratamento de erros idiomático em Zig.


# Tratamento de Erros em Zig: Guia Completo

O sistema de erros de Zig é uma das características mais distintivas desta linguagem de programação de sistemas. Diferente de exceptions (Java, C++, Python) ou Result types (Rust), Zig adota uma abordagem única baseada em **error sets** e **error unions** que é explícita, eficiente e integrada à linguagem.

Neste guia completo, você vai aprender tudo sobre tratamento de erros em Zig: desde os conceitos básicos até padrões avançados usados em código de produção.

> **Pré-requisitos:** Conhecimento básico de Zig (variáveis, funções, tipos). Recomendamos ter lido [Structs, Enums e Unions](/tutoriais/structs-enums-unions-zig/) antes deste guia.

---

## Índice

1. [Visão Geral do Sistema de Erros](#visão-geral-do-sistema-de-erros)
2. [Error Sets](#error-sets)
3. [Error Unions](#error-unions)
4. [Propagando Erros com `try`](#propagando-erros-com-try)
5. [Tratando Erros com `catch`](#tratando-erros-com-catch)
6. [Valores Padrão com `orelse`](#valores-padrão-com-orelse)
7. [`errdefer` — Defer Condicional](#errdefer--defer-condicional)
8. [Erros em Métodos e Structs](#erros-em-métodos-e-structs)
9. [Error Inference](#error-inference)
10. [Padrões Comuns](#padrões-comuns)
11. [Comparação com Outras Linguagens](#comparação-com-outras-linguagens)
12. [Melhores Práticas](#melhores-práticas)
13. [FAQ](#faq)
14. [Próximos Passos](#próximos-passos)

---

## Visão Geral do Sistema de Erros

### A Filosofia Zig

Zig segue o princípio de **"erros são valores"**, não exceções. Isso significa:

1. **Erros são explícitos** — toda função que pode falhar declara isso no tipo de retorno
2. **Não há exceções** — não existe mecanismo de unwinding ou catch-all
3. **Zero overhead** — tratamento de erros não custa em runtime quando não falha
4. **Composição simples** — é fácil combinar e propagar erros

### Comparativo Rápido

| Aspecto | Exceptions (Java/C++) | Result<T,E> (Rust) | Zig Error Unions |
|---------|----------------------|-------------------|------------------|
| Erro é... | Exception lançada | Enum Ok/Err | Valor especial |
| Declaração | `throws` (opcional) | `Result<T,E>` | `!T` ou `E!T` |
| Propagação | Automaticamente | `?` operator | `try` keyword |
| Overhead | Alto (stack unwinding) | Baixo | Zero |
| Type safety | Runtime | Compile time | Compile time |

---

## Error Sets

Error sets são conjuntos nomeados de erros possíveis. Funcionam como enums, mas são dedicados a erros.

### Declaração Básica

```zig
const std = @import("std");

// Definindo um error set
const ErroArquivo = error{
    NaoEncontrado,
    PermissaoNegada,
    EmUso,
    EspacoInsuficiente,
};

// Error set vazio (nenhum erro possível)
const SemErro = error{};
```

### Usando Error Sets

```zig
// Função que retorna um erro específico
fn abrirArquivo(caminho: []const u8) ErroArquivo!Arquivo {
    if (caminho.len == 0) return error.NaoEncontrado;
    // ... código real ...
    return Arquivo{};
}

// Struct de arquivo (exemplo)
const Arquivo = struct {
    handle: i32,
};
```

### Error Set Universal: `anyerror`

`anyerror` é o error set que contém todos os erros possíveis:

```zig
// Pode retornar qualquer erro
fn operacaoArriscada() anyerror!void {
    return error.AlgumErro;
}

// Útil para callbacks genéricos
const CallbackErro = fn () anyerror!void;
```

---

## Error Unions

Error unions representam "um valor OU um erro". São o coração do sistema de erros em Zig.

### Sintaxe

```zig
// T!E significa: valor do tipo T ou erro do error set E
const resultado: i32!ErroArquivo = 42;
const erro: i32!ErroArquivo = error.NaoEncontrado;

// Erro set implícito (infere do contexto)
const valor: !i32 = calcular();  // !i32 = anyerror!i32
```

### Criando Error Unions

```zig
// Sucesso: retorna o valor diretamente
fn sucesso() !i32 {
    return 42;
}

// Erro: retorna um valor do error set
fn falha() !i32 {
    return error.Falha;
}

// Múltiplos erros possíveis
const MeuErro = error{ ErroA, ErroB };
const OutroErro = error{ ErroC };

fn podeFalharDeVariasFormas() (MeuErro || OutroErro)!i32 {
    // Pode retornar ErroA, ErroB ou ErroC
    return error.ErroA;
}
```

### Acessando Valores de Error Unions

```zig
const resultado = podeFalhar();

// 1. If com capture
if (resultado) |valor| {
    std.debug.print("Sucesso: {d}\n", .{valor});
} else |err| {
    std.debug.print("Erro: {}\n", .{err});
}

// 2. Switch
switch (resultado) {
    .Ok => |valor| std.debug.print("Valor: {d}\n", .{valor}),
    .Err => |err| std.debug.print("Erro: {}\n", .{err}),
}

// 3. While com erro (para iteradores que falham)
while (iterador.next()) |item| {
    // processa item
} else |err| {
    // iterador falhou
}
```

---

## Propagando Erros com `try`

A palavra-chave `try` é a forma mais comum de propagar erros. Se o valor for um erro, retorna imediatamente da função.

### Sintaxe Básica

```zig
const std = @import("std");

const ErroOperacao = error{ DivisaoPorZero, Overflow };

fn divisaoSegura(a: i32, b: i32) ErroOperacao!i32 {
    if (b == 0) return error.DivisaoPorZero;
    return @divTrunc(a, b);
}

// Usando try
fn calcularMedia(a: i32, b: i32) ErroOperacao!i32 {
    const soma = try adicionar(a, b);    // Propaga erro se falhar
    return try divisaoSegura(soma, 2);    // Propaga erro se falhar
}

fn adicionar(a: i32, b: i32) ErroOperacao!i32 {
    const resultado = @addWithOverflow(a, b);
    if (resultado[1] != 0) return error.Overflow;
    return resultado[0];
}
```

### Como `try` Funciona

```zig
// Isso:
const x = try funcao();

// É equivalente a:
const x = funcao() catch |err| return err;
```

### Cadeias de `try`

```zig
fn processarDados() !void {
    const arquivo = try abrirArquivo("dados.txt");
    const conteudo = try lerArquivo(arquivo);
    const parseado = try parseJSON(conteudo);
    try salvarNoBanco(parseado);
}
```

Se qualquer operação falhar, a função retorna imediatamente com o erro.

---

## Tratando Erros com `catch`

`catch` permite tratar erros localmente, sem propagar.

### Sintaxe Básica

```zig
// catch com valor padrão
const resultado = podeFalhar() catch 0;

// catch com bloco
const resultado = podeFalhar() catch |err| {
    std.debug.print("Erro: {}\n", .{err});
    0  // valor padrão
};
```

### Exemplos Práticos

```zig
const std = @import("std");

const ErroConfig = error{ ConfigNaoEncontrada, ConfigInvalida };

fn carregarConfig(caminho: []const u8) ErroConfig!Config {
    // ... tenta carregar ...
    return Config{};
}

const Config = struct {
    porta: u16 = 8080,
    host: []const u8 = "localhost",
};

pub fn main() void {
    // Valor padrão simples
    const config = carregarConfig("app.conf") catch Config{
        .porta = 3000,
        .host = "0.0.0.0",
    };
    
    // Tratamento específico
    const porta = parsePorta("8080") catch |err| {
        std.debug.print("Porta inválida: {}\n", .{err});
        8080  // fallback
    };
    
    // Log e re-trow
    const dados = buscarDados() catch |err| {
        std.log.err("Falha ao buscar dados: {}", .{err});
        return;  // ou: return err;
    };
}

fn parsePorta(texto: []const u8) !u16 {
    return std.fmt.parseInt(u16, texto, 10);
}

fn buscarDados() ![]const u8 {
    return "dados";
}
```

### Catch com Unreachable

Quando você sabe que uma operação não vai falhar (mas o compilador não sabe):

```zig
// "Eu garanto que isso não falha"
const numero = parseInt("42", 10) catch unreachable;

// ⚠️ Use com cuidado! Falha = comportamento indefinido
```

---

## Valores Padrão com `orelse`

`orelse` é similar a `catch`, mas específico para optional types (`?T`).

### Sintaxe

```zig
const talvezValor: ?i32 = null;

// orelse com valor
const valor = talvezValor orelse 0;

// orelse com bloco
const valor = talvezValor orelse {
    std.debug.print("Usando padrão\n");
    0
};

// orelse com retorno
const valor = talvezValor orelse return error.ValorNulo;
```

### Combinando com `try` e `catch`

```zig
const std = @import("std");

const Usuario = struct {
    id: u64,
    nome: []const u8,
    email: ?[]const u8,  // opcional
};

fn enviarEmail(usuario: Usuario) !void {
    // orelse para optional
    const email = usuario.email orelse {
        std.debug.print("Usuário sem email\n");
        return;
    };
    
    // try para error union
    try enviarPara(email);
}

fn enviarPara(email: []const u8) !void {
    _ = email;
    // ...
}
```

---

## `errdefer` — Defer Condicional

`errdefer` executa código somente se a função retornar um erro. É essencial para cleanup em funções que falham.

### Problema: Sem `errdefer`

```zig
fn processarArquivos() !void {
    const arquivo1 = try abrir("a.txt");
    // Se falhar aqui, arquivo1 não é fechado!
    
    const arquivo2 = try abrir("b.txt");
    // Se falhar aqui, arquivo2 não é fechado!
    
    // Processamento...
    
    arquivo2.fechar();
    arquivo1.fechar();
}
```

### Solução: Com `errdefer`

```zig
fn processarArquivos() !void {
    const arquivo1 = try abrir("a.txt");
    errdefer arquivo1.fechar();  // Só executa se der erro
    
    const arquivo2 = try abrir("b.txt");
    errdefer arquivo2.fechar();  // Só executa se der erro
    
    // Processamento (pode falhar)...
    try processar(arquivo1, arquivo2);
    
    // Se chegou aqui, deu tudo certo
    // errdefers NÃO executam
    arquivo2.fechar();
    arquivo1.fechar();
}

const Arquivo = struct {
    nome: []const u8,
    
    fn abrir(nome: []const u8) !Arquivo {
        return Arquivo{ .nome = nome };
    }
    
    fn fechar(self: Arquivo) void {
        std.debug.print("Fechando: {s}\n", .{self.nome});
    }
};

const std = @import("std");

fn processar(a: Arquivo, b: Arquivo) !void {
    _ = a; _ = b;
    // ...
}
```

### `errdefer` com Capture

```zig
fn operacaoComplexa() !void {
    const recurso = try alocar();
    errdefer |err| {
        // Acesso ao erro que causou o defer
        std.log.err("Cleanup devido a: {}", .{err});
        liberar(recurso);
    }
    
    try usar(recurso);
}

fn alocar() !i32 { return 42; }
fn liberar(x: i32) void { _ = x; }
fn usar(x: i32) !void { _ = x; }
```

### Ordem de Execução

```zig
fn demonstrarOrdem() !void {
    errdefer std.debug.print("errdefer 1\n");
    errdefer std.debug.print("errdefer 2\n");
    defer std.debug.print("defer 1\n");
    defer std.debug.print("defer 2\n");
    
    return error.Falha;
    // Imprime:
    // errdefer 2
    // errdefer 1
}
```

**Regra:** `errdefer`s executam na ordem inversa (LIFO), antes de retornar o erro.

---

## Erros em Métodos e Structs

### Métodos que Falham

```zig
const std = @import("std");

const Contador = struct {
    valor: i32,
    maximo: i32,
    
    const Erro = error{ LimiteExcedido };
    
    pub fn incrementar(self: *Contador) Erro!void {
        if (self.valor >= self.maximo) {
            return error.LimiteExcedido;
        }
        self.valor += 1;
    }
    
    pub fn novo(maximo: i32) Contador {
        return .{
            .valor = 0,
            .maximo = maximo,
        };
    }
};

pub fn main() !void {
    var contador = Contador.novo(5);
    
    var i: i32 = 0;
    while (i < 10) : (i += 1) {
        contador.incrementar() catch |err| {
            std.debug.print("Erro na iteração {d}: {}\n", .{ i, err });
            break;
        };
    }
    
    std.debug.print("Valor final: {d}\n", .{contador.valor});
}
```

### Error Set como Campo

```zig
const ResultadoOperacao = struct {
    sucesso: bool,
    erro: ?ErroDetalhado,
    dados: ?[]const u8,
};

const ErroDetalhado = struct {
    codigo: u32,
    mensagem: []const u8,
    timestamp: i64,
};
```

---

## Error Inference

Zig pode inferir error sets automaticamente em muitos casos.

### Inferência Automática

```zig
// O compilador infere: error{DivisaoPorZero}!i32
fn dividir(a: i32, b: i32) !i32 {
    if (b == 0) return error.DivisaoPorZero;
    return @divTrunc(a, b);
}

// Error set combinado automaticamente
fn operacaoComplexa() !void {
    const x = try dividir(10, 2);      // pode dar DivisaoPorZero
    const y = try raizQuadrada(x);      // pode dar RaizNegativa
    // Error set resultante: {DivisaoPorZero, RaizNegativa}
}

fn raizQuadrada(x: i32) !i32 {
    if (x < 0) return error.RaizNegativa;
    return 0;
}
```

### Inferência em Loops

```zig
// Error set é inferido de todas as iterações possíveis
fn processarLista(itens: []const i32) !void {
    for (itens) |item| {
        try processar(item);  // erro pode vir de qualquer iteração
    }
}
```

### Inferência Recursiva

```zig
fn fibonacci(n: u32) error{Overflow}!u32 {
    if (n <= 1) return n;
    
    const a = try fibonacci(n - 1);
    const b = try fibonacci(n - 2);
    
    return std.math.add(u32, a, b) catch return error.Overflow;
}

const std = @import("std");
```

---

## Padrões Comuns

### 1. Wrap Errors (Encapsulamento)

```zig
const ErroBaixoNivel = error{ Io, Timeout };
const ErroAltoNivel = error{ CarregamentoFalhou };

fn carregarDados() ErroAltoNivel!Dados {
    const arquivo = abrirArquivo() catch |err| {
        std.log.err("Falha de IO: {}", .{err});
        return error.CarregamentoFalhou;
    };
    _ = arquivo;
    return Dados{};
}

const Dados = struct {};
fn abrirArquivo() ErroBaixoNivel!i32 { return 0; }

const std = @import("std");
```

### 2. Early Return

```zig
fn processarEntrada(entrada: []const u8) !Resultado {
    if (entrada.len == 0) return error.EntradaVazia;
    if (entrada.len > 1000) return error.EntradaMuitoGrande;
    
    const parseado = try parse(entrada);
    const validado = try validar(parseado);
    
    return try transformar(validado);
}

const Resultado = struct {};
fn parse(e: []const u8) !i32 { _ = e; return 0; }
fn validar(x: i32) !i32 { _ = x; return 0; }
fn transformar(x: i32) !Resultado { _ = x; return Resultado{}; }
```

### 3. Accumulate Errors

```zig
const std = @import("std");

const ErroValidacao = error{
    NomeVazio,
    EmailInvalido,
    SenhaCurta,
};

const ErrosValidacao = struct {
    erros: [3]?ErroValidacao,
    count: usize,
    
    pub fn novo() ErrosValidacao {
        return .{
            .erros = .{ null, null, null },
            .count = 0,
        };
    }
    
    pub fn adicionar(self: *ErrosValidacao, erro: ErroValidacao) void {
        if (self.count < self.erros.len) {
            self.erros[self.count] = erro;
            self.count += 1;
        }
    }
    
    pub fn temErros(self: ErrosValidacao) bool {
        return self.count > 0;
    }
};

fn validarUsuario(nome: []const u8, email: []const u8, senha: []const u8) ErrosValidacao {
    var erros = ErrosValidacao.novo();
    
    if (nome.len == 0) erros.adicionar(error.NomeVazio);
    if (!contemArroba(email)) erros.adicionar(error.EmailInvalido);
    if (senha.len < 8) erros.adicionar(error.SenhaCurta);
    
    return erros;
}

fn contemArroba(s: []const u8) bool {
    for (s) |c| {
        if (c == '@') return true;
    }
    return false;
}
```

### 4. Retry Pattern

```zig
const std = @import("std");

const ErroRede = error{ Timeout, ConexaoRecusada };

fn enviarComRetry(
    dados: []const u8,
    maxTentativas: u32,
) ErroRede!void {
    var tentativa: u32 = 0;
    
    while (tentativa < maxTentativas) : (tentativa += 1) {
        enviar(dados) catch |err| {
            if (tentativa == maxTentativas - 1) return err;
            
            std.log.warn("Tentativa {d} falhou: {}. Retentando...", .{
                tentativa + 1, err
            });
            
            std.time.sleep(1 * std.time.ns_per_s);
            continue;
        };
        
        return;  // Sucesso
    }
}

fn enviar(dados: []const u8) ErroRede!void {
    _ = dados;
    // ...
}
```

---

## Comparação com Outras Linguagens

### Zig vs Exceptions (Java/Python/C++)

**Exceptions:**
```python
# Python
def dividir(a, b):
    if b == 0:
        raise ZeroDivisionError("Divisão por zero")
    return a / b

try:
    resultado = dividir(10, 0)
except ZeroDivisionError as e:
    print(f"Erro: {e}")
```

**Zig:**
```zig
fn dividir(a: i32, b: i32) error{DivisaoPorZero}!i32 {
    if (b == 0) return error.DivisaoPorZero;
    return @divTrunc(a, b);
}

const resultado = dividir(10, 0) catch |err| {
    std.debug.print("Erro: {}\n", .{err});
    0
};
```

**Vantagens do Zig:**
- Nenhum overhead em caso de sucesso
- Erros são parte do tipo (type-safe)
- Não há unwinding de stack
- Performance previsível

### Zig vs Result (Rust)

**Rust:**
```rust
fn dividir(a: i32, b: i32) -> Result<i32, Erro> {
    if b == 0 { return Err(Erro::DivisaoPorZero); }
    Ok(a / b)
}

let resultado = dividir(10, 2)?;  // ? propaga erro
```

**Zig:**
```zig
fn dividir(a: i32, b: i32) !i32 {
    if (b == 0) return error.DivisaoPorZero;
    return @divTrunc(a, b);
}

const resultado = try dividir(10, 2);  // try propaga erro
```

**Diferenças:**
- Rust usa `Result<T,E>` (enum genérico)
- Zig usa error unions integrados (`!T`)
- Ambos são zero-cost e type-safe
- Zig é mais sintaticamente leve

### Zig vs Go

**Go:**
```go
func dividir(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("divisão por zero")
    }
    return a / b, nil
}

resultado, err := dividir(10, 0)
if err != nil {
    log.Println(err)
}
```

**Zig:**
```zig
fn dividir(a: i32, b: i32) !i32 {
    if (b == 0) return error.DivisaoPorZero;
    return @divTrunc(a, b);
}

const resultado = dividir(10, 0) catch |err| {
    std.log.err("{}", .{err});
    0
};
```

**Vantagens do Zig:**
- Erros são verificados em compile-time (não pode ignorar)
- `try` é mais conciso que `if err != nil`
- Não precisa retornar múltiplos valores

---

## Melhores Práticas

### 1. Seja Específico nos Error Sets

```zig
// ✅ Bom: error set específico
const ErroParse = error{
    NumeroInvalido,
    Overflow,
};

// ❌ Ruim: error set genérico demais
fn parseNumero() anyerror!i32 {  // Evite anyerror quando possível
    // ...
}
```

### 2. Documente Erros Possíveis

```zig
/// Parseia uma string para i32.
/// Retorna error.NumeroInvalido se a string não for um número.
/// Retorna error.Overflow se o número for muito grande.
fn parseInt(texto: []const u8) !i32 {
    // ...
}
```

### 3. Use `errdefer` para Cleanup

```zig
fn alocarRecursos() !Recursos {
    const a = try alocarA();
    errdefer liberarA(a);
    
    const b = try alocarB();
    errdefer liberarB(b);
    
    return Recursos{ .a = a, .b = b };
}
```

### 4. Não Ignore Erros Silenciosamente

```zig
// ❌ Ruim: erro ignorado
_ = funcaoQuePodeFalhar();

// ✅ Bom: trate ou propague
funcaoQuePodeFalhar() catch |err| {
    std.log.err("Falha: {}", .{err});
};

// Ou: propague explicitamente
try funcaoQuePodeFalhar();
```

### 5. Use `orelse` para Optionals, `catch` para Errors

```zig
// ✅ Correto
const valor = talvezValor orelse 0;        // optional
const resultado = podeFalhar() catch 0;    // error union

// ❌ Não funciona
// const x = podeFalhar() orelse 0;  // ERRO: orelse é para ?T, não !T
```

### 6. Considere `unreachable` Apenas Quando Certeza Absoluta

```zig
// ✅ Seguro: pós-condições verificadas
const resultado = parseInt("42") catch unreachable;  // Literal conhecido

// ❌ Perigoso: entrada do usuário
const entrada = lerLinha();
const num = parseInt(entrada) catch unreachable;  // Pode falhar!
```

---

## FAQ

### Qual a diferença entre `try` e `catch`?

- **`try`**: Propaga o erro para o chamador (early return)
- **`catch`**: Trata o erro localmente

```zig
// try: propaga
const x = try podeFalhar();  // retorna erro se falhar

// catch: trata aqui
const x = podeFalhar() catch 0;  // usa 0 se falhar
```

### Como criar um error set vazio?

```zig
const SemErro = error{};  // Nenhum erro possível
```

Isso é útil para generic code.

### Posso converter entre error sets?

```zig
const ErroPequeno = error{ A, B };
const ErroGrande = error{ A, B, C, D };

// ErroPequeno converte para ErroGrande automaticamente
fn funcao() ErroPequeno!void {
    return error.A;
}

fn outra() ErroGrande!void {
    return funcao();  // OK: ErroPequeno ⊆ ErroGrande
}
```

### Como verificar se um valor é erro?

```zig
const resultado = podeFalhar();

if (resultado) |valor| {
    // é valor
} else |err| {
    // é erro
}
```

### O que acontece se eu não tratar um erro?

O compilador Zig **rejeita** código que ignora error unions:

```zig
const x = podeFalhar();  // ERRO: error union não tratado!

// Correto:
const x = try podeFalhar();              // propaga
const x = podeFalhar() catch 0;          // trata
_ = podeFalhar() catch |e| std.log.err("{}", .{e});  // explícito
```

### Como retornar múltiplos erros possíveis?

```zig
// Use || para unir error sets
fn operacao() (error{ A, B, C })!void {
    // pode retornar A, B ou C
}

// Ou use anyerror
fn operacaoGenerica() anyerror!void {
    // pode retornar qualquer erro
}
```

### `anyerror` tem custo?

Sim. `anyerror` usa mais memória (pode ser u16 ou u32) comparado a error sets específicos que podem ser u8. Prefira error sets específicos quando possível.

---

## Próximos Passos

Agora que você domina tratamento de erros em Zig, continue seu aprendizado:

### Conteúdo Relacionado

1. **[Structs, Enums e Unions em Zig](/tutoriais/structs-enums-unions-zig/)** — Complemente com tipos compostos
2. **[Gerenciamento de Memória em Zig](/tutoriais/gerenciamento-de-memoria-zig/)** — Aprenda sobre allocators e error handling com memória
3. **[Parsing JSON em Zig](/tutoriais/parsing-json-zig/)** — Veja error handling na prática com parsing
4. **[Criando uma CLI em Zig](/tutoriais/cli-em-zig/)** — Aplique tratamento de erros em aplicações reais
5. **[Zig Build System](/tutoriais/zig-build-system/)** — Configure testes e builds que aproveitam o sistema de erros do Zig
6. **[Zig vs Rust](/artigos/zig-vs-rust/)** — Compare abordagens de error handling

### Pratique

- Implemente um parser com error handling completo
- Crie uma biblioteca com error sets bem definidos
- Refatore código usando `errdefer` para garantir cleanup

### Recursos Adicionais

- [Zig Guide - Errors](https://zig.guide/standard-library/errors/)
- [Zighelp - Error Handling](https://zighelp.org/chapter-1/)
- [Documentação Oficial - Errors](https://ziglang.org/documentation/master/#Errors)

---

## Resumo

| Conceito | Sintaxe | Uso |
|----------|---------|-----|
| **Error Set** | `error{ A, B }` | Definir conjunto de erros |
| **Error Union** | `E!T` ou `!T` | "T ou erro" |
| **Propagação** | `try expr` | Retorna erro automaticamente |
| **Tratamento** | `expr catch` | Lida com erro localmente |
| **Optional** | `?T` | "T ou null" |
| **Fallback** | `expr orelse` | Valor padrão para optional |
| **Cleanup** | `errdefer` | Executa só se der erro |

O sistema de erros de Zig é uma das features mais poderosas da linguagem. Ao tornar erros parte do sistema de tipos, Zig garante que falhas sejam tratadas explicitamente — sem exceptions caras, sem Result types verbosos, apenas código limpo e type-safe. Se você vem de outras linguagens, compare com a abordagem de <a href="https://golang.com.br/artigos/go-error-handling/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">tratamento de erros em Go</a> (múltiplos retornos) ou o <a href="https://rustlang.com.br/artigos/rust-error-handling/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Result&lt;T, E&gt; de Rust</a>.

---

*Escrito por [Camila](/sobre/) para [ZigLang Brasil](/). Última atualização: 10 de fevereiro de 2026.*

*Achou algum erro? Tem sugestões? [Contribua no GitHub](https://github.com/seu-repo/ziglangbr)*
