Writer Interface em Zig — O que é e Como Usar

Writer Interface em Zig — O que é e Como Usar

Definição

A Writer interface em Zig é o padrão utilizado pela biblioteca padrão para abstração de escrita de dados. Qualquer tipo que forneça uma função write com a assinatura correta pode ser usado como Writer. Isso permite escrever código genérico que funciona com stdout, arquivos, buffers em memória, sockets de rede ou qualquer outro destino de dados.

Em Zig, interfaces são implementadas via anytype (duck typing em comptime) ou via o tipo concreto std.io.Writer, que usa uma vtable para dispatch dinâmico.

Por que Writer Interface Importa

  1. Código genérico: Uma função que aceita anytype writer funciona com qualquer destino.
  2. Testabilidade: Escrever em buffer para testes, em arquivo para produção.
  3. Composição: Writers podem ser encadeados (buffered writer, counting writer, etc.).
  4. Padrão da std lib: Formatação, logging e serialização usam a Writer interface.

Exemplo Prático

Função Genérica com Writer

const std = @import("std");

fn escreverRelatorio(writer: anytype, nome: []const u8, pontos: u32) !void {
    try writer.print("Relatório de: {s}\n", .{nome});
    try writer.print("Pontuação: {}\n", .{pontos});
    try writer.print("Status: {s}\n", .{
        if (pontos >= 70) "Aprovado" else "Reprovado",
    });
    try writer.writeAll("---\n");
}

pub fn main() !void {
    // Escrever para stdout
    const stdout = std.io.getStdOut().writer();
    try escreverRelatorio(stdout, "Ana", 85);
    try escreverRelatorio(stdout, "Bruno", 60);
}

Escrever em Buffer (para Testes)

const std = @import("std");

fn formatarSaudacao(writer: anytype, nome: []const u8) !void {
    try writer.print("Olá, {s}!", .{nome});
}

test "formatar saudação" {
    var buffer: [256]u8 = undefined;
    var stream = std.io.fixedBufferStream(&buffer);
    const writer = stream.writer();

    try formatarSaudacao(writer, "Zig Brasil");

    const resultado = stream.getWritten();
    try std.testing.expectEqualStrings("Olá, Zig Brasil!", resultado);
}

Buffered Writer para Performance

const std = @import("std");

pub fn main() !void {
    const arquivo = try std.fs.cwd().createFile("saida.txt", .{});
    defer arquivo.close();

    // Buffered writer reduz syscalls de escrita
    var buf_writer = std.io.bufferedWriter(arquivo.writer());
    const writer = buf_writer.writer();

    for (0..1000) |i| {
        try writer.print("Linha {}\n", .{i});
    }

    // Flush final para garantir que tudo foi escrito
    try buf_writer.flush();
}

Writers Comuns na std lib

WriterDescrição
std.io.getStdOut().writer()Saída padrão (stdout)
std.io.getStdErr().writer()Saída de erro (stderr)
file.writer()Escrita em arquivo
stream.writer()Escrita em fixedBufferStream
std.io.bufferedWriter(w)Writer com buffer
std.io.countingWriter(w)Writer que conta bytes escritos

Armadilhas Comuns

  • Flush: Buffered writers exigem flush() no final para garantir que dados pendentes sejam escritos.
  • Erros de escrita: Sempre trate os erros com try. Escrever pode falhar (disco cheio, socket fechado).
  • anytype vs Writer concreto: Use anytype para funções simples. Use std.io.Writer quando precisar armazenar o writer em uma struct.
  • Performance: Sem buffer, cada print pode gerar uma syscall. Use bufferedWriter para escrita intensiva.

Termos Relacionados

Tutoriais Relacionados

Continue aprendendo Zig

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