Cheatsheet: Controle de Fluxo em Zig

Cheatsheet: Controle de Fluxo em Zig

Referência completa para todas as estruturas de controle de fluxo em Zig, incluindo padrões avançados com optionals e error unions.

If / Else

// If básico
if (condicao) {
    // código
}

// If / else
if (x > 0) {
    std.debug.print("positivo\n", .{});
} else if (x < 0) {
    std.debug.print("negativo\n", .{});
} else {
    std.debug.print("zero\n", .{});
}

// If como expressão
const abs = if (x >= 0) x else -x;

// If com captura de optional
var talvez: ?i32 = 42;
if (talvez) |valor| {
    std.debug.print("Valor: {}\n", .{valor});
} else {
    std.debug.print("É null\n", .{});
}

// If com captura de ponteiro (para modificar)
if (talvez) |*ptr| {
    ptr.* += 1;
}

// If com error union
const resultado: anyerror!i32 = calcular();
if (resultado) |valor| {
    std.debug.print("Ok: {}\n", .{valor});
} else |err| {
    std.debug.print("Erro: {}\n", .{err});
}

Switch

// Switch básico
const x: i32 = 5;
switch (x) {
    1 => std.debug.print("um\n", .{}),
    2, 3 => std.debug.print("dois ou três\n", .{}),
    4...10 => std.debug.print("entre 4 e 10\n", .{}),
    else => std.debug.print("outro\n", .{}),
}

// Switch como expressão
const texto = switch (x) {
    1 => "um",
    2 => "dois",
    else => "outro",
};

// Switch com enum
const Cor = enum { vermelho, verde, azul };
const cor: Cor = .verde;

switch (cor) {
    .vermelho => doVermelho(),
    .verde => doVerde(),
    .azul => doAzul(),
}
// Switch em enum é exaustivo — não precisa de else se cobrir todos os casos

// Switch com tagged union
const Valor = union(enum) {
    inteiro: i64,
    texto: []const u8,
    nenhum: void,
};

const v = Valor{ .inteiro = 42 };
switch (v) {
    .inteiro => |i| std.debug.print("Int: {}\n", .{i}),
    .texto => |t| std.debug.print("Texto: {s}\n", .{t}),
    .nenhum => std.debug.print("Nenhum\n", .{}),
}

// Switch com captura de ponteiro
var valor: u8 = 5;
switch (valor) {
    3...7 => |*v| {
        v.* = 0;  // modificar o valor original
    },
    else => {},
}

// Switch com múltiplos ranges
switch (char) {
    'a'...'z' => handleMinuscula(char),
    'A'...'Z' => handleMaiuscula(char),
    '0'...'9' => handleDigito(char),
    else => handleOutro(char),
}

While

// While básico
var i: u32 = 0;
while (i < 10) {
    std.debug.print("{} ", .{i});
    i += 1;
}

// While com continue expression (como "increment" do for em C)
var j: u32 = 0;
while (j < 10) : (j += 1) {
    std.debug.print("{} ", .{j});
}

// While com captura de optional
var it = iterador();
while (it.next()) |item| {
    processarItem(item);
}

// While com else (executa quando condição é falsa)
var k: u32 = 0;
const resultado = while (k < 10) : (k += 1) {
    if (k == 5) break k;
} else blk: {
    break :blk @as(u32, 0);  // valor se nenhum break foi executado
};

// While com captura de erro
while (leitor.readByte()) |byte| {
    processarByte(byte);
} else |err| {
    if (err != error.EndOfStream) return err;
}

// While infinito
while (true) {
    // loop infinito — use break para sair
    if (deveSair()) break;
}

For

// For sobre array/slice
const arr = [_]i32{ 1, 2, 3, 4, 5 };
for (arr) |valor| {
    std.debug.print("{} ", .{valor});
}

// For com índice
for (arr, 0..) |valor, i| {
    std.debug.print("[{}]={} ", .{ i, valor });
}

// For com ponteiro (para modificar)
var mut = [_]i32{ 1, 2, 3 };
for (&mut) |*elem| {
    elem.* *= 2;
}

// For sobre múltiplos arrays
const nomes = [_][]const u8{ "Ana", "Bruno", "Carlos" };
const idades = [_]u32{ 25, 30, 35 };
for (nomes, idades) |nome, idade| {
    std.debug.print("{s} tem {} anos\n", .{ nome, idade });
}

// For com range
for (0..10) |i| {
    std.debug.print("{} ", .{i});
}

// For como expressão (com break)
const encontrado = for (arr) |valor| {
    if (valor == 3) break valor;
} else @as(i32, -1);

Break e Continue

// Break — sair do loop
for (0..100) |i| {
    if (i == 50) break;
    std.debug.print("{} ", .{i});
}

// Continue — pular para próxima iteração
for (0..10) |i| {
    if (i % 2 == 0) continue;  // pular pares
    std.debug.print("{} ", .{i});  // só ímpares
}

// Break com valor (loop como expressão)
const resultado = for (arr) |valor| {
    if (valor > 3) break valor;
} else @as(i32, 0);

// Break nomeado — sair de loop externo
outer: for (0..10) |i| {
    for (0..10) |j| {
        if (i * j > 30) break :outer;
        std.debug.print("({},{})", .{ i, j });
    }
}

// Continue nomeado
outer: for (0..10) |i| {
    for (0..10) |j| {
        if (j % 2 == 0) continue :outer;
        _ = i;
    }
}

Blocos Nomeados

// Bloco nomeado com valor de retorno
const resultado = blk: {
    var acumulador: i32 = 0;
    for (arr) |valor| {
        acumulador += valor;
    }
    break :blk acumulador;
};

// Blocos nomeados para escape de loops aninhados
const pos = outer: for (matrix, 0..) |linha, i| {
    for (linha, 0..) |valor, j| {
        if (valor == alvo) break :outer .{ i, j };
    }
} else .{ @as(usize, 0), @as(usize, 0) };

Padrões com Optionals

// Encadeamento de optionals
const config = getConfig();
const valor = if (config) |c|
    if (c.secao) |s|
        s.chave
    else
        null
else
    null;

// orelse para valor padrão
const seguro = getOptional() orelse valorPadrao;

// orelse com bloco
const resultado = getOptional() orelse blk: {
    std.log.warn("Usando fallback\n", .{});
    break :blk calcularFallback();
};

// orelse unreachable (assert que não é null)
const garantido = getOptional() orelse unreachable;

Padrões com Erros

// try — propagar erro
const valor = try funcaoQuePoderFalhar();

// catch — tratar erro
const valor2 = funcaoQuePoderFalhar() catch |err| {
    std.log.err("Falha: {}\n", .{err});
    return err;
};

// catch com valor padrão
const valor3 = funcaoQuePoderFalhar() catch 0;

// switch no erro
funcaoQuePoderFalhar() catch |err| switch (err) {
    error.ArquivoNaoEncontrado => {
        std.log.warn("Arquivo não existe\n", .{});
    },
    error.PermissaoNegada => {
        std.log.err("Sem permissão\n", .{});
        return err;
    },
    else => return err,
};

Tabela de Referência

EstruturaUso
if (cond) exprCondicional simples
if (opt) |v| exprDesempacotar optional
if (err_union) |v| expr else |e| exprDesempacotar error union
switch (val) { ... }Seleção múltipla
while (cond) exprLoop com condição
while (cond) : (inc) exprLoop com incremento
for (slice) |elem| exprIteração sobre coleção
for (slice, 0..) |e, i| exprIteração com índice
for (0..n) |i| exprRange loop
breakSair do loop
break :label valorSair com valor
continuePróxima iteração

Veja Também

Continue aprendendo Zig

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