Orelse em Zig — O que é e Como Usar

Orelse em Zig — O que é e Como Usar

Definição

O operador orelse em Zig é usado para desembrulhar (unwrap) valores opcionais (?T), fornecendo um valor alternativo caso o optional seja null. É o equivalente ao operador ?? de C# ou ao ?: de Kotlin — uma forma concisa de dizer “use este valor, ou se for null, use aquele outro”.

A sintaxe é: optional_value orelse fallback.

Por que Orelse Importa

  1. Concisão: Substitui blocos if/else verbosos para desembrulhar optionals.
  2. Segurança: Fornece valor de fallback em vez de panic.
  3. Encadeamento: Pode ser encadeado e combinado com outras expressões.
  4. Legibilidade: Expressa a intenção de “valor padrão” de forma clara.

Exemplo Prático

Uso Básico

const std = @import("std");

fn buscarConfiguracao(chave: []const u8) ?u32 {
    if (std.mem.eql(u8, chave, "porta")) return 8080;
    if (std.mem.eql(u8, chave, "timeout")) return 30;
    return null;
}

pub fn main() void {
    const porta = buscarConfiguracao("porta") orelse 3000;
    const max_conn = buscarConfiguracao("max_conexoes") orelse 100;

    std.debug.print("Porta: {}\n", .{porta});       // 8080
    std.debug.print("Max conn: {}\n", .{max_conn});  // 100 (fallback)
}

Orelse com Bloco

const valor = obterOptional() orelse blk: {
    std.log.warn("Valor não encontrado, usando padrão", .{});
    break :blk valor_padrao;
};

Orelse com Return

fn processarDados(talvez_dados: ?[]const u8) !void {
    const dados = talvez_dados orelse return error.DadosAusentes;

    // Aqui, dados é []const u8 — desembrulhado
    std.debug.print("Processando {} bytes\n", .{dados.len});
}

Orelse com Unreachable

// Quando temos CERTEZA que não é null
const lista = [_]u32{ 10, 20, 30 };
const primeiro = std.mem.indexOfScalar(u32, &lista, 10) orelse unreachable;
// primeiro = 0

Encadeando com Operações

fn encontrarUsuario(id: u32) ?*Usuario {
    // busca no cache ou banco
}

fn nomeDoUsuario(id: u32) []const u8 {
    const usuario = encontrarUsuario(id) orelse return "Desconhecido";
    return usuario.nome;
}

Comparação: orelse vs if

// Com orelse (conciso)
const resultado = obterValor() orelse 0;

// Equivalente com if (verboso)
const resultado2 = if (obterValor()) |v| v else 0;

Orelse vs Catch

OperadorFunciona comPropósito
orelse?T (optional)Valor default para null
catch!T (error union)Tratamento de erro
const opt: ?u32 = null;
const a = opt orelse 42;          // orelse com optional

const err: anyerror!u32 = error.Falha;
const b = err catch 42;           // catch com error union

Casos de Uso Comuns

O orelse aparece naturalmente em situações de busca, configuração e parsing:

const std = @import("std");

// Leitura de variável de ambiente com padrão
fn porta() u16 {
    const env = std.posix.getenv("PORT") orelse return 8080;
    return std.fmt.parseInt(u16, env, 10) catch 8080;
}

// Busca em slice com padrão
fn encontrarPosicao(haystack: []const u32, needle: u32) usize {
    return std.mem.indexOfScalar(u32, haystack, needle) orelse haystack.len;
}

// Acesso a mapa com fallback
fn obterConfig(mapa: std.StringHashMap([]const u8), chave: []const u8) []const u8 {
    return mapa.get(chave) orelse "valor_padrão";
}

Orelse em Encadeamentos

Um padrão poderoso é encadear múltiplos orelse para tentar fontes alternativas:

fn obterToken(env: ?[]const u8, arquivo: ?[]const u8, padrao: []const u8) []const u8 {
    return env orelse arquivo orelse padrao;
}

Neste exemplo, env é tentado primeiro. Se for null, tenta arquivo. Se também for null, usa padrao. O encadeamento é avaliado da esquerda para a direita e para no primeiro valor não-null.

Comparação com Outras Linguagens

LinguagemOperador equivalenteObservação
ZigorelseApenas para ?T
Kotlin?: (Elvis)Para tipos anuláveis
C#??Para tipos anuláveis
Swift??Para Optional<T>
Rust.unwrap_or(v)Método em Option<T>
JavaScript??Nullish coalescing

A diferença fundamental do Zig é que orelse é verificado em tempo de compilação — você não pode usar orelse em um !T (error union) por engano; o compilador rejeita imediatamente.

Armadilhas Comuns

  • Confundir com catch: orelse é para optionals (?T); catch é para error unions (!T). Usar o errado causa erro de compilação.
  • Orelse com unreachable irresponsável: orelse unreachable causa panic se o valor for null. Só use quando tiver certeza absoluta.
  • Efeitos colaterais no fallback: O fallback do orelse só é avaliado se o optional for null (avaliação preguiçosa). Não dependa dele para efeitos colaterais obrigatórios.
  • Esquecer que orelse desembrulha: Após orelse, o tipo é T, não ?T. O optional já foi resolvido.

Termos Relacionados

  • Optional — Tipo que pode ser null
  • Catch — Equivalente de orelse para erros
  • Try — Propagação de erros
  • Unreachable — Marcador de código inalcançável

Tutoriais Relacionados

Continue aprendendo Zig

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