Cheatsheet: Formatação (fmt) em Zig

Cheatsheet: Formatação (fmt) em Zig

O módulo std.fmt é responsável por toda a formatação de texto em Zig. Diferente de linguagens com interpolação de string, Zig usa especificadores de formato dentro de strings literais, combinados com tuplas anônimas (.{...}) para os argumentos. Esse sistema é verificado em tempo de compilação — se o formato não bater com os argumentos, o compilador avisa imediatamente.

Funções de Saída

std.debug.print — Debug para stderr

const std = @import("std");

pub fn main() void {
    // Saída rápida para stderr (sem try necessário)
    std.debug.print("Valor: {d}\n", .{42});
    std.debug.print("Nome: {s}, Idade: {d}\n", .{ "Ana", 25 });
}

stdout.print — Saída formatada para stdout

const std = @import("std");

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    try stdout.print("Olá, {s}!\n", .{"mundo"});
    try stdout.print("Resultado: {d:.2}\n", .{3.14159});

    // writeAll — sem formatação
    try stdout.writeAll("Texto direto sem formato\n");
}

std.log — Sistema de logging

const std = @import("std");

pub fn main() void {
    std.log.info("Servidor iniciado na porta {d}", .{8080});
    std.log.warn("Cache com {d}% de uso", .{85});
    std.log.err("Falha ao conectar: {s}", .{"timeout"});
    std.log.debug("Variável x = {d}", .{42});
}

Especificadores de Formato

Tabela de Referência

EspecificadorTipoExemploSaída
{d}Inteiro decimal{d} com 4242
{x}Inteiro hexadecimal minúsculo{x} com 255ff
{X}Inteiro hexadecimal maiúsculo{X} com 255FF
{o}Inteiro octal{o} com 810
{b}Inteiro binário{b} com 101010
{s}String/slice de bytes{s} com "zig"zig
{c}Caractere (u8){c} com 65A
{e}Float em notação científica{e} com 3.143.14e0
{}Formato padrão do tipo{} com 4242
{any}Qualquer tipo (debug){any} com structrepresentação debug

Inteiros

const x: i32 = 42;

std.debug.print("Decimal:     {d}\n", .{x});      // 42
std.debug.print("Hexadecimal: {x}\n", .{x});      // 2a
std.debug.print("Hex maiúsc.: {X}\n", .{x});      // 2A
std.debug.print("Octal:       {o}\n", .{x});      // 52
std.debug.print("Binário:     {b}\n", .{x});      // 101010

// Com prefixo
std.debug.print("Hex: 0x{x}\n", .{x});            // 0x2a
std.debug.print("Bin: 0b{b}\n", .{x});            // 0b101010

Floats

const pi: f64 = 3.14159265358979;

std.debug.print("Padrão:     {d}\n", .{pi});       // 3.14159265358979
std.debug.print("2 decimais: {d:.2}\n", .{pi});    // 3.14
std.debug.print("5 decimais: {d:.5}\n", .{pi});    // 3.14159
std.debug.print("Científico: {e}\n", .{pi});       // 3.14159e0

Strings

const nome = "Zig Brasil";

std.debug.print("String:  {s}\n", .{nome});        // Zig Brasil

Preenchimento e Alinhamento

// Preenchimento com largura mínima
std.debug.print("[{d:>10}]\n", .{42});     // [        42]  — alinhado à direita
std.debug.print("[{d:<10}]\n", .{42});     // [42        ]  — alinhado à esquerda
std.debug.print("[{d:^10}]\n", .{42});     // [    42    ]  — centralizado

// Preenchimento com caractere personalizado
std.debug.print("[{d:0>8}]\n", .{42});     // [00000042]  — zeros à esquerda
std.debug.print("[{d:_>8}]\n", .{42});     // [______42]  — underscores
std.debug.print("[{s:*^20}]\n", .{"ZIG"}); // [********ZIG*********]

// Hex com largura fixa
std.debug.print("0x{x:0>4}\n", .{@as(u16, 10)});  // 0x000a
std.debug.print("0x{X:0>8}\n", .{@as(u32, 255)}); // 0x000000FF

bufPrint — Formatação em Buffer

const std = @import("std");

pub fn main() !void {
    var buffer: [256]u8 = undefined;

    // Formatar em buffer estático
    const resultado = try std.fmt.bufPrint(&buffer, "Nome: {s}, Idade: {d}", .{ "Carlos", 30 });

    std.debug.print("Resultado: {s}\n", .{resultado});
    std.debug.print("Tamanho: {d}\n", .{resultado.len});
}

allocPrint — Formatação com Alocação

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Formatar com alocação dinâmica
    const mensagem = try std.fmt.allocPrint(allocator, "Usuário {s} logou às {d}:{d:0>2}", .{ "admin", 14, 5 });
    defer allocator.free(mensagem);

    std.debug.print("{s}\n", .{mensagem});
    // Saída: "Usuário admin logou às 14:05"
}

comptimePrint — Formatação em comptime

// String formatada em tempo de compilação
const nome_campo = std.fmt.comptimePrint("campo_{d}", .{42});
// nome_campo == "campo_42" (constante comptime)

Formatação Customizada

Você pode implementar a função format em qualquer struct para controlar como ela é exibida:

const std = @import("std");

const Ponto = struct {
    x: f32,
    y: f32,

    pub fn format(
        self: Ponto,
        comptime fmt: []const u8,
        options: std.fmt.FormatOptions,
        writer: anytype,
    ) !void {
        _ = fmt;
        _ = options;
        try writer.print("({d:.1}, {d:.1})", .{ self.x, self.y });
    }
};

pub fn main() void {
    const p = Ponto{ .x = 3.5, .y = 7.2 };
    std.debug.print("Ponto: {}\n", .{p});
    // Saída: Ponto: (3.5, 7.2)
}

Formatando Diferentes Tipos

Optionals

const valor: ?i32 = 42;
const nulo: ?i32 = null;

std.debug.print("Valor: {?d}\n", .{valor});  // Valor: 42
std.debug.print("Nulo:  {?d}\n", .{nulo});   // Nulo:  null

Ponteiros

var x: i32 = 42;
const ptr = &x;

std.debug.print("Endereço: {*}\n", .{ptr});   // Endereço: 0x7fff5a...
std.debug.print("Valor:    {d}\n", .{ptr.*});  // Valor:    42

Slices e Arrays

const dados = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
const texto = "Olá";

std.debug.print("Hex: {x}\n", .{std.fmt.fmtSliceHexLower(&dados)});
// Saída: Hex: deadbeef

std.debug.print("Bytes: {s}\n", .{texto});

Enums

const Cor = enum { vermelho, verde, azul };
const c = Cor.verde;

std.debug.print("Cor: {s}\n", .{@tagName(c)});  // Cor: verde

Erros Comuns

// ERRO: Número de argumentos não bate
// std.debug.print("{d} {d}\n", .{42}); // faltou segundo argumento

// ERRO: Especificador errado para o tipo
// std.debug.print("{d}\n", .{"texto"}); // {d} não funciona com string

// ERRO: Esquecer o \n
// std.debug.print("sem newline", .{}); // saída pode não aparecer imediatamente

// CORRETO: Usar {s} para strings, {d} para números
std.debug.print("{s}: {d}\n", .{ "resultado", 42 });

Veja Também

Continue aprendendo Zig

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