Optional em Zig — O que é e Como Usar

Optional em Zig — O que é e Como Usar

Definição

Um Optional em Zig é um tipo representado pelo operador ? que pode conter ou um valor válido do tipo T ou null. A sintaxe ?T declara um optional do tipo T. Diferentemente de linguagens como C onde qualquer ponteiro pode ser null, em Zig a possibilidade de nulidade é explícita no sistema de tipos.

Optionals eliminam uma das maiores fontes de bugs em programação: o acesso a valores nulos sem verificação.

Por que Optionals Importam

  1. Null safety: O compilador obriga você a verificar se o valor existe antes de usá-lo.
  2. Expressividade: A assinatura da função comunica claramente que “pode não haver valor”.
  3. Zero custo: Para ponteiros, ?*T tem o mesmo tamanho que *T (null é representado como 0).
  4. Diferente de erro: Optional indica ausência, não falha. Use Error Union quando houver motivo da falha.

Exemplo Prático

Uso Básico

const std = @import("std");

fn encontrar(haystack: []const u8, needle: u8) ?usize {
    for (haystack, 0..) |char, indice| {
        if (char == needle) return indice;
    }
    return null; // Não encontrou
}

pub fn main() void {
    const texto = "Zig Brasil";

    if (encontrar(texto, 'B')) |indice| {
        std.debug.print("Encontrado na posição {}\n", .{indice});
    } else {
        std.debug.print("Não encontrado\n", .{});
    }
}

Unwrap com orelse

const valor: ?u32 = null;
const resultado = valor orelse 42; // resultado = 42

const outro: ?u32 = 10;
const resultado2 = outro orelse 42; // resultado2 = 10

Unwrap com if

fn processar(talvez_dados: ?[]const u8) void {
    if (talvez_dados) |dados| {
        // dados é []const u8 — desembrulhado, sem null
        std.debug.print("Dados: {s}\n", .{dados});
    } else {
        std.debug.print("Sem dados\n", .{});
    }
}

Unwrap com while

fn proximoValor(iterador: *Iterador) ?u32 {
    // retorna null quando acabar
}

// while com optional — itera até null
while (proximoValor(&iter)) |valor| {
    std.debug.print("{}\n", .{valor});
}

Optional de Ponteiro

const Node = struct {
    valor: i32,
    proximo: ?*Node, // Ponteiro que pode ser null
};

fn ultimo(node: *Node) *Node {
    var atual = node;
    while (atual.proximo) |prox| {
        atual = prox;
    }
    return atual;
}

Encadeamento com .?

const config: ?*Config = obterConfig();
// .? é equivalente a unwrap forçado (panic se null)
const porta = config.?.porta;

Cuidado: .? causa panic se o valor for null. Prefira if ou orelse.

Optional vs Error Union

Característica?T (Optional)!T (Error Union)
SignificaValor pode estar ausenteOperação pode falhar
Informação extraNenhuma (só null)Qual erro ocorreu
Operadororelsecatch
ExemploBusca em listaLeitura de arquivo

Armadilhas Comuns

  • Usar .? sem verificação: O unwrap forçado (.?) causa panic se o valor for null. Use if ou orelse para segurança.
  • Confundir ?T com !T: Optional indica ausência; error union indica falha com motivo. Escolha o tipo correto.
  • Optionals aninhados: ??T é válido mas raramente útil e pode causar confusão. Repense o design se chegar nesse ponto.
  • Usar optional quando um valor default é melhor: Se sempre há um valor razoável de fallback, considere usar o valor diretamente em vez de optional.

Termos Relacionados

Tutoriais Relacionados

Continue aprendendo Zig

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