@call em Zig — Referência e Exemplos

@call em Zig

O @call invoca uma função com controle avançado sobre como a chamada é realizada. Permite forçar inlining, prevenir tail calls, controlar otimizações de chamada e especificar o stack frame. Útil para código de alta performance, recursão e interoperabilidade.

Sintaxe

@call(modifier: std.builtin.CallModifier, function: anytype, args: anytype) ReturnType

Parâmetros

  • modifier (CallModifier): Controle sobre como a chamada é feita.
  • function: A função a ser chamada.
  • args: Tupla com os argumentos da função.

Valor de retorno

Retorna o mesmo tipo que a função chamada retornaria.

Modifiers disponíveis

ModifierDescrição
.autoComportamento padrão (igual a chamada normal)
.always_inlineForçar inlining (erro se não for possível)
.never_inlineNunca inline (sempre chamada de função)
.never_tailNunca otimizar como tail call
.compile_timeForçar avaliação em comptime

Exemplos práticos

Exemplo 1: Forçar inlining

const std = @import("std");

fn somaRapida(a: u64, b: u64) u64 {
    return a + b;
}

pub fn main() void {
    // Forçar que somaRapida seja inlined
    const resultado = @call(.always_inline, somaRapida, .{
        @as(u64, 42),
        @as(u64, 58),
    });

    std.debug.print("Soma: {}\n", .{resultado}); // 100
}

Exemplo 2: Prevenir tail call em recursão

const std = @import("std");

fn fatorial(n: u64) u64 {
    if (n <= 1) return 1;

    // Prevenir tail call para manter stack frame (útil para debug)
    return n * @call(.never_tail, fatorial, .{n - 1});
}

pub fn main() void {
    std.debug.print("10! = {}\n", .{fatorial(10)}); // 3628800
}

Exemplo 3: Chamada genérica de função

const std = @import("std");

fn chamarComLog(funcao: anytype, args: anytype) @TypeOf(@call(.auto, funcao, args)) {
    std.debug.print("Chamando função...\n", .{});
    const resultado = @call(.auto, funcao, args);
    std.debug.print("Função retornou.\n", .{});
    return resultado;
}

fn multiplicar(a: i32, b: i32) i32 {
    return a * b;
}

fn saudar(nome: []const u8) void {
    std.debug.print("Olá, {s}!\n", .{nome});
}

pub fn main() void {
    const produto = chamarComLog(multiplicar, .{ @as(i32, 6), @as(i32, 7) });
    std.debug.print("Produto: {}\n", .{produto}); // 42

    chamarComLog(saudar, .{"Zig Brasil"});
}

Casos de uso comuns

  1. Performance: Forçar inlining de funções críticas em hot paths.
  2. Debugging: Prevenir tail calls para manter stack traces completos.
  3. Wrappers genéricos: Criar decoradores/interceptadores de funções.
  4. Benchmarks: Prevenir que o compilador otimize chamadas de teste.
  5. Recursão controlada: Garantir que recursão use o stack conforme esperado.

@call vs chamada normal

// Equivalentes:
const r1 = funcao(a, b);
const r2 = @call(.auto, funcao, .{ a, b });

// Mas @call permite controle extra:
const r3 = @call(.always_inline, funcao, .{ a, b });  // Forçar inline
const r4 = @call(.never_tail, funcao, .{ a, b });     // Sem tail call

Builtins relacionados

Tutoriais relacionados

Continue aprendendo Zig

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