Como Formatar Strings com std.fmt em Zig

Como Formatar Strings com std.fmt em Zig

O sistema de formatação de Zig (std.fmt) é poderoso e seguro em tempo de compilação. Diferente de printf em C, o compilador verifica os tipos dos argumentos e detecta erros antes da execução.

Especificadores Básicos de Formato

Cada especificador começa com { e termina com }. O tipo do argumento determina qual especificador usar.

const std = @import("std");

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

    // {d} - inteiros decimais
    try stdout.print("Inteiro: {d}\n", .{42});

    // {s} - strings (slices de u8)
    try stdout.print("String: {s}\n", .{"Olá Zig"});

    // {c} - caractere único (u8)
    try stdout.print("Caractere: {c}\n", .{'A'});

    // {x} - hexadecimal minúsculo
    try stdout.print("Hex: {x}\n", .{@as(u32, 255)});

    // {X} - hexadecimal maiúsculo
    try stdout.print("HEX: {X}\n", .{@as(u32, 255)});

    // {o} - octal
    try stdout.print("Octal: {o}\n", .{@as(u32, 255)});

    // {b} - binário
    try stdout.print("Binário: {b}\n", .{@as(u8, 42)});

    // {e} - notação científica
    try stdout.print("Científico: {e}\n", .{@as(f64, 12345.6789)});

    // {} - formato padrão (baseado no tipo)
    try stdout.print("Padrão: {}\n", .{@as(u32, 42)});

    // {any} - formato para qualquer tipo (debug)
    const ponto = .{ .x = 10, .y = 20 };
    try stdout.print("Debug: {any}\n", .{ponto});
}

Saída esperada:

Inteiro: 42
String: Olá Zig
Caractere: A
Hex: ff
HEX: FF
Octal: 377
Binário: 101010
Científico: 1.23456789e4
Padrão: 42
Debug: .{ .x = 10, .y = 20 }

Formatação de Números com Precisão

Controle casas decimais e largura de campo para números.

const std = @import("std");

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

    // Precisão de casas decimais
    try stdout.print("2 casas:  {d:.2}\n", .{pi});
    try stdout.print("4 casas:  {d:.4}\n", .{pi});
    try stdout.print("8 casas:  {d:.8}\n", .{pi});

    // Valores monetários
    const preco: f64 = 1299.90;
    try stdout.print("Preço: R$ {d:.2}\n", .{preco});

    // Porcentagem
    const taxa: f64 = 0.1575;
    try stdout.print("Taxa: {d:.2}%\n", .{taxa * 100.0});
}

Saída esperada:

2 casas:  3.14
4 casas:  3.1416
8 casas:  3.14159265
Preço: R$ 1299.90
Taxa: 15.75%

Largura de Campo e Alinhamento

Defina a largura mínima e o alinhamento do texto formatado.

const std = @import("std");

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

    // Largura mínima com alinhamento à direita (padrão para números)
    try stdout.print("|{d:10}|\n", .{@as(i32, 42)});
    try stdout.print("|{d:10}|\n", .{@as(i32, 12345)});

    // Alinhamento à esquerda com <
    try stdout.print("|{s:<10}| esquerda\n", .{"abc"});

    // Alinhamento à direita com >
    try stdout.print("|{s:>10}| direita\n", .{"abc"});

    // Alinhamento centralizado com ^
    try stdout.print("|{s:^10}| centro\n", .{"abc"});

    // Preenchimento com caractere personalizado
    try stdout.print("|{s:-<10}|\n", .{"abc"});
    try stdout.print("|{s:->10}|\n", .{"abc"});
    try stdout.print("|{s:-^10}|\n", .{"abc"});

    // Preenchimento com zeros para números
    try stdout.print("Com zeros: {d:0>8}\n", .{@as(u32, 42)});
}

Saída esperada:

|        42|
|     12345|
|abc       | esquerda
|       abc| direita
|   abc    | centro
|abc-------|
|-------abc|
|---abc----|
Com zeros: 00000042

Formatação em Buffer Fixo

Use std.fmt.bufPrint para formatar em um buffer sem alocação dinâmica.

const std = @import("std");

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

    var buf: [256]u8 = undefined;

    // Formatar em buffer
    const msg = try std.fmt.bufPrint(&buf, "Olá, {s}! Você tem {d} mensagens.", .{ "Maria", @as(u32, 5) });
    try stdout.print("{s}\n", .{msg});

    // Formatar data
    const data = try std.fmt.bufPrint(&buf, "{d:0>2}/{d:0>2}/{d}", .{ @as(u32, 21), @as(u32, 2), @as(u32, 2026) });
    try stdout.print("Data: {s}\n", .{data});

    // Formatar endereço IP
    const ip = try std.fmt.bufPrint(&buf, "{d}.{d}.{d}.{d}", .{ @as(u8, 192), @as(u8, 168), @as(u8, 1), @as(u8, 100) });
    try stdout.print("IP: {s}\n", .{ip});
}

Saída esperada:

Olá, Maria! Você tem 5 mensagens.
Data: 21/02/2026
IP: 192.168.1.100

Formatação com Alocação Dinâmica

Use std.fmt.allocPrint quando precisar de strings alocadas dinamicamente.

const std = @import("std");

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

    // Formatar com alocação
    const nome = "Zig Brasil";
    const membros: u32 = 1500;
    const texto = try std.fmt.allocPrint(allocator, "Comunidade {s} com {d} membros", .{ nome, membros });
    defer allocator.free(texto);
    try stdout.print("{s}\n", .{texto});

    // Construir JSON simples
    const json = try std.fmt.allocPrint(
        allocator,
        "{{\"nome\": \"{s}\", \"idade\": {d}, \"ativo\": true}}",
        .{ "Carlos", @as(u32, 30) },
    );
    defer allocator.free(json);
    try stdout.print("JSON: {s}\n", .{json});
}

Saída esperada:

Comunidade Zig Brasil com 1500 membros
JSON: {"nome": "Carlos", "idade": 30, "ativo": true}

Implementar Formatação Personalizada

Você pode implementar a função format para seus próprios tipos.

const std = @import("std");

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

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

const Cor = struct {
    r: u8,
    g: u8,
    b: u8,

    pub fn format(
        self: Cor,
        comptime fmt: []const u8,
        options: std.fmt.FormatOptions,
        writer: anytype,
    ) !void {
        _ = fmt;
        _ = options;
        try writer.print("#{X:0>2}{X:0>2}{X:0>2}", .{ self.r, self.g, self.b });
    }
};

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

    const p = Ponto{ .x = 3.14159, .y = 2.71828 };
    try stdout.print("Ponto: {}\n", .{p});

    const cor = Cor{ .r = 255, .g = 128, .b = 0 };
    try stdout.print("Cor: {}\n", .{cor});
}

Saída esperada:

Ponto: (3.14, 2.72)
Cor: #FF8000

Tabela de Especificadores

EspecificadorTipoDescrição
{d}InteirosDecimal
{x} / {X}InteirosHexadecimal minúsculo/maiúsculo
{o}InteirosOctal
{b}InteirosBinário
{s}[]const u8String
{c}u8Caractere
{e}FloatsNotação científica
{any}QualquerRepresentação de debug
{}QualquerFormato padrão do tipo

Veja Também

Continue aprendendo Zig

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