Cheatsheet: Funções em Zig

Cheatsheet: Funções em Zig

Referência completa sobre declaração e uso de funções em Zig, incluindo genéricos, comptime e funções de ordem superior.

Declaração Básica

// Função simples
fn somar(a: i32, b: i32) i32 {
    return a + b;
}

// Função pública (acessível de outros módulos)
pub fn calcular(x: f64) f64 {
    return x * x;
}

// Função sem retorno
fn imprimir(msg: []const u8) void {
    std.debug.print("{s}\n", .{msg});
}

// Função que pode falhar (retorna error union)
fn dividir(a: f64, b: f64) !f64 {
    if (b == 0) return error.DivisaoPorZero;
    return a / b;
}

// Função com conjunto de erros específico
const MathError = error{ DivisaoPorZero, Overflow };
fn dividirSeguro(a: f64, b: f64) MathError!f64 {
    if (b == 0) return error.DivisaoPorZero;
    return a / b;
}

// Função que nunca retorna
fn panico(msg: []const u8) noreturn {
    @panic(msg);
}

Parâmetros

// Parâmetros são sempre imutáveis
fn processar(valor: i32) i32 {
    // valor = 10;  // ERRO: não pode modificar parâmetro
    return valor + 1;
}

// Ponteiro para modificar valor
fn dobrar(ptr: *i32) void {
    ptr.* *= 2;
}

// Slice como parâmetro
fn soma(numeros: []const i32) i64 {
    var total: i64 = 0;
    for (numeros) |n| {
        total += n;
    }
    return total;
}

// Parâmetro comptime
fn criarArray(comptime N: usize) [N]i32 {
    return [_]i32{0} ** N;
}

// Parâmetro anytype (genérico)
fn maximo(a: anytype, b: @TypeOf(a)) @TypeOf(a) {
    return if (a > b) a else b;
}

Retorno de Múltiplos Valores

// Retornar struct anônima (tupla)
fn divmod(a: i32, b: i32) struct { quociente: i32, resto: i32 } {
    return .{
        .quociente = @divTrunc(a, b),
        .resto = @mod(a, b),
    };
}

// Uso
const r = divmod(17, 5);
std.debug.print("Q={} R={}\n", .{ r.quociente, r.resto });

// Retornar array
fn minMax(slice: []const i32) [2]i32 {
    var min = slice[0];
    var max = slice[0];
    for (slice[1..]) |v| {
        if (v < min) min = v;
        if (v > max) max = v;
    }
    return .{ min, max };
}

Funções Genéricas

// Função genérica com anytype
fn trocar(a: anytype, b: @TypeOf(a)) void {
    _ = a;
    _ = b;
}

// Função genérica com tipo comptime
fn List(comptime T: type) type {
    return struct {
        items: []T,
        len: usize,

        const Self = @This();

        pub fn get(self: Self, index: usize) T {
            return self.items[index];
        }
    };
}

// Uso
const IntList = List(i32);
_ = IntList;

// Genérico com restrições via @typeInfo
fn somar_generico(comptime T: type, a: T, b: T) T {
    const info = @typeInfo(T);
    switch (info) {
        .int, .comptime_int => return a + b,
        .float, .comptime_float => return a + b,
        else => @compileError("Tipo não suportado para soma"),
    }
}

Funções de Ordem Superior

// Tipo de ponteiro de função
const Operacao = *const fn (i32, i32) i32;

fn aplicar(op: Operacao, a: i32, b: i32) i32 {
    return op(a, b);
}

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

// Uso
const resultado1 = aplicar(somar, 3, 4);       // 7
const resultado2 = aplicar(multiplicar, 3, 4);  // 12

// Map genérico
fn map(
    comptime T: type,
    comptime R: type,
    items: []const T,
    f: *const fn (T) R,
    resultado: []R,
) void {
    for (items, 0..) |item, i| {
        resultado[i] = f(item);
    }
}

// Filter genérico
fn filter(
    comptime T: type,
    items: []const T,
    pred: *const fn (T) bool,
    resultado: []T,
) []T {
    var count: usize = 0;
    for (items) |item| {
        if (pred(item)) {
            resultado[count] = item;
            count += 1;
        }
    }
    return resultado[0..count];
}

Métodos (Funções em Structs)

const Retangulo = struct {
    largura: f64,
    altura: f64,

    // Método de instância (recebe self)
    pub fn area(self: Retangulo) f64 {
        return self.largura * self.altura;
    }

    // Método que modifica (recebe ponteiro para self)
    pub fn escalar(self: *Retangulo, fator: f64) void {
        self.largura *= fator;
        self.altura *= fator;
    }

    // Método "estático" (não recebe self)
    pub fn quadrado(lado: f64) Retangulo {
        return .{ .largura = lado, .altura = lado };
    }
};

// Uso
var r = Retangulo{ .largura = 5.0, .altura = 3.0 };
const a = r.area();       // chamada de método
r.escalar(2.0);            // modifica r
const q = Retangulo.quadrado(4.0);  // "construtor"
_ = a;
_ = q;

Inline e Comptime

// Função inline
inline fn fast_add(a: i32, b: i32) i32 {
    return a + b;
}

// Função comptime
fn fibonacci(comptime n: u32) comptime_int {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

const fib10 = fibonacci(10);  // calculado em tempo de compilação

// Bloco comptime dentro de função
fn inicializar() [256]u8 {
    comptime {
        var tabela: [256]u8 = undefined;
        for (&tabela, 0..) |*elem, i| {
            elem.* = @intCast(i);
        }
        return tabela;
    }
}

Defer em Funções

fn processarArquivo(path: []const u8) !void {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();  // fecha ao sair, independentemente de como

    const data = try file.readToEndAlloc(allocator, max_size);
    defer allocator.free(data);  // defers executam em ordem LIFO

    errdefer std.log.err("Falha ao processar: {s}\n", .{path});
    // errdefer só executa se função retornar erro

    try processar(data);
}

Recursão

// Recursão simples
fn fatorial(n: u64) u64 {
    if (n <= 1) return 1;
    return n * fatorial(n - 1);
}

// Recursão com comptime
fn gerarTipo(comptime depth: usize) type {
    if (depth == 0) return i32;
    return struct {
        valor: gerarTipo(depth - 1),
    };
}

Padrões Comuns

// Função init / deinit (construtor / destrutor)
const Buffer = struct {
    data: []u8,
    allocator: std.mem.Allocator,

    pub fn init(allocator: std.mem.Allocator, size: usize) !Buffer {
        return .{
            .data = try allocator.alloc(u8, size),
            .allocator = allocator,
        };
    }

    pub fn deinit(self: *Buffer) void {
        self.allocator.free(self.data);
    }
};

// Uso
var buf = try Buffer.init(allocator, 1024);
defer buf.deinit();

// Função com contexto (closure simulada)
fn criarContador() struct {
    valor: i32,

    pub fn incrementar(self: *@This()) i32 {
        self.valor += 1;
        return self.valor;
    }
} {
    return .{ .valor = 0 };
}

Tabela de Referência

PadrãoExemplo
Função simplesfn f(x: i32) i32
Função públicapub fn f() void
Retorna errofn f() !i32
Erro específicofn f() MyError!i32
Nunca retornafn f() noreturn
Parâmetro genéricofn f(x: anytype) @TypeOf(x)
Parâmetro comptimefn f(comptime T: type) type
Ponteiro de função*const fn (i32) i32
Métodofn f(self: Self) void
Método mutávelfn f(self: *Self) void
Inlineinline fn f() void

Veja Também

Continue aprendendo Zig

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