Cheatsheet: Strategy em Zig

Strategy em Zig

O padrão Strategy define uma família de algoritmos, encapsula cada um deles e os torna intercambiáveis. Em Zig, existem três formas principais de implementar: comptime (zero custo em runtime), ponteiros de função (flexível em runtime) e tagged unions (type-safe com exaustividade verificada pelo compilador).

Quando Usar

  • Diferentes algoritmos de ordenação, compressão, criptografia
  • Estratégias de retry, cache ou roteamento
  • Formatação de saída (JSON, CSV, XML)
  • Validação com regras configuráveis

Strategy com comptime (Custo Zero)

const std = @import("std");

fn Compressor(comptime estrategia: enum { gzip, lz4, nenhuma }) type {
    return struct {
        pub fn comprimir(dados: []const u8) []const u8 {
            return switch (estrategia) {
                .gzip => {
                    // lógica de compressão gzip
                    _ = dados;
                    return "dados_gzip";
                },
                .lz4 => {
                    _ = dados;
                    return "dados_lz4";
                },
                .nenhuma => dados,
            };
        }
    };
}

// Tipo resolvido em compilação — zero overhead
const CompressorGzip = Compressor(.gzip);
const CompressorLz4 = Compressor(.lz4);

Strategy com Ponteiros de Função

const std = @import("std");

const EstrategiaOrdenacao = *const fn ([]i32) void;

fn bubbleSort(dados: []i32) void {
    for (0..dados.len) |_| {
        for (0..dados.len - 1) |j| {
            if (dados[j] > dados[j + 1]) {
                const temp = dados[j];
                dados[j] = dados[j + 1];
                dados[j + 1] = temp;
            }
        }
    }
}

fn insertionSort(dados: []i32) void {
    for (1..dados.len) |i| {
        const chave = dados[i];
        var j: usize = i;
        while (j > 0 and dados[j - 1] > chave) {
            dados[j] = dados[j - 1];
            j -= 1;
        }
        dados[j] = chave;
    }
}

const Ordenador = struct {
    estrategia: EstrategiaOrdenacao,

    pub fn ordenar(self: *const Ordenador, dados: []i32) void {
        self.estrategia(dados);
    }

    pub fn setEstrategia(self: *Ordenador, nova: EstrategiaOrdenacao) void {
        self.estrategia = nova;
    }
};

pub fn main() void {
    var dados = [_]i32{ 5, 2, 8, 1, 9, 3 };
    var ordenador = Ordenador{ .estrategia = bubbleSort };

    ordenador.ordenar(&dados);
    // Trocar estratégia em runtime
    ordenador.setEstrategia(insertionSort);
}

Strategy com Tagged Union

const std = @import("std");

const FormatoSaida = union(enum) {
    json,
    csv: struct { separador: u8 = ',' },
    texto: struct { largura: u16 = 80 },

    pub fn formatar(self: FormatoSaida, dados: anytype, writer: anytype) !void {
        switch (self) {
            .json => {
                try std.json.stringify(dados, .{}, writer);
                try writer.writeAll("\n");
            },
            .csv => |opts| {
                _ = opts;
                // formatação CSV...
                try writer.writeAll("dados,csv\n");
            },
            .texto => |opts| {
                _ = opts;
                try writer.writeAll("Saída texto\n");
            },
        }
    }
};

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    const formato = FormatoSaida.json;
    try formato.formatar(.{ .nome = "Zig" }, stdout);
}

Quando Evitar

  • Quando só existe uma estratégia (e não se planeja extensão)
  • Se comptime resolve o problema sem necessidade de troca em runtime
  • Poucas variantes simples — um switch direto pode ser mais claro

Veja Também

  • Factory — Criar a estratégia certa baseada em config
  • Observer — Notificar sobre mudança de estratégia
  • Type Erasure — Interfaces genéricas em runtime
  • Comptime — Strategy resolvido na compilação
  • Enums e Unions — Tagged unions para estratégias

Continue aprendendo Zig

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