Cheatsheet: Singleton em Zig

Singleton em Zig

O padrão Singleton garante que uma classe/struct tenha apenas uma instância durante toda a execução do programa, fornecendo um ponto de acesso global a ela. Em Zig, esse padrão é implementado de forma diferente de linguagens OOP tradicionais, utilizando variáveis globais, std.once e comptime.

Quando Usar

  • Gerenciador de configuração global
  • Pool de conexões com banco de dados
  • Sistema de logging centralizado
  • Cache global da aplicação
  • Acesso a hardware (ex: GPIO em sistemas embarcados)

Implementação Básica

Singleton com variável global

const std = @import("std");

const Logger = struct {
    nivel: NivelLog,
    arquivo: ?std.fs.File,

    const NivelLog = enum { debug, info, warn, err };

    // Instância global única
    var instancia: ?Logger = null;
    var mutex = std.Thread.Mutex{};

    pub fn obterInstancia() *Logger {
        mutex.lock();
        defer mutex.unlock();

        if (instancia == null) {
            instancia = Logger{
                .nivel = .info,
                .arquivo = null,
            };
        }
        return &instancia.?;
    }

    pub fn log(self: *Logger, nivel: NivelLog, mensagem: []const u8) void {
        if (@intFromEnum(nivel) < @intFromEnum(self.nivel)) return;
        std.debug.print("[{s}] {s}\n", .{ @tagName(nivel), mensagem });
    }
};

pub fn main() void {
    const logger = Logger.obterInstancia();
    logger.log(.info, "Aplicação iniciada");
    logger.log(.warn, "Recurso quase esgotado");
    logger.log(.debug, "Esta mensagem não aparece (nível < info)");

    // Em qualquer parte do código, mesma instância
    const mesmo_logger = Logger.obterInstancia();
    mesmo_logger.log(.err, "Erro crítico!");
}

Singleton com std.once (thread-safe garantido)

const std = @import("std");

const Config = struct {
    porta: u16,
    host: []const u8,
    max_conexoes: u32,

    var instancia: Config = undefined;
    var once = std.once(inicializar);

    fn inicializar() void {
        instancia = Config{
            .porta = 8080,
            .host = "localhost",
            .max_conexoes = 100,
        };
    }

    pub fn obter() *Config {
        once.call(); // executado apenas uma vez, thread-safe
        return &instancia;
    }
};

pub fn main() void {
    const config = Config.obter();
    std.debug.print("Servidor: {s}:{d}\n", .{ config.host, config.porta });

    // Sempre retorna a mesma instância
    const config2 = Config.obter();
    std.debug.print("Max conexões: {d}\n", .{config2.max_conexoes});
}

Singleton Genérico com comptime

fn Singleton(comptime T: type, comptime initFn: fn () T) type {
    return struct {
        var instancia: ?T = null;
        var mutex = std.Thread.Mutex{};

        pub fn obter() *T {
            mutex.lock();
            defer mutex.unlock();

            if (instancia == null) {
                instancia = initFn();
            }
            return &instancia.?;
        }

        pub fn resetar() void {
            mutex.lock();
            defer mutex.unlock();
            instancia = null;
        }
    };
}

// Uso:
const MeuSingleton = Singleton(MinhaStruct, MinhaStruct.criar);
const inst = MeuSingleton.obter();

Quando Evitar

  • Testes unitários: Singletons criam estado global que dificulta testes isolados. Prefira Dependency Injection quando testabilidade é prioridade.
  • Acoplamento excessivo: Se muitas partes do código dependem do singleton, considere passar a dependência explicitamente.
  • Concorrência pesada: Para dados compartilhados entre muitas threads, considere um Pool de Objetos ou dados por thread.

Alternativa Idiomática em Zig

Em Zig, muitas vezes é preferível simplesmente passar a dependência como parâmetro, seguindo a filosofia de tornar tudo explícito:

const Logger = struct {
    nivel: NivelLog,
    // ...
};

fn processarRequisicao(logger: *Logger, dados: []const u8) !void {
    logger.log(.info, "Processando requisição");
    // ...
}

Veja Também

Continue aprendendo Zig

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