anytype em Zig: O Que É, Exemplos e Genéricos

anytype em Zig: O Que É, Exemplos e Genéricos

Resposta direta: anytype em Zig é o parâmetro cujo tipo o compilador infere automaticamente a partir do argumento da chamada. Serve para escrever funções genéricas sem sintaxe <T>: cada uso gera uma especialização estática em comptime, sem tipagem dinâmica e sem overhead de runtime.

Use anytype quando a função só precisa “aceitar o que for passado” e operar sobre esse valor — por exemplo, writers, helpers matemáticos e formatadores. Se vários parâmetros precisam do mesmo tipo nomeado, prefira comptime T: type.

Resumo rápido

PerguntaResposta curta
O que é anytype?Parâmetro com tipo inferido na chamada
É runtime?Não — especialização em comptime
Como ler o tipo?@TypeOf(param) e @typeInfo
Alternativa explícitacomptime T: type
Uso clássicoWriters, print/log, helpers genéricos

Definição

anytype é uma anotação de tipo especial em Zig que permite que o compilador infira o tipo de um parâmetro a partir do argumento passado na chamada da função. É o mecanismo principal para criar funções genéricas em Zig sem precisar de uma sintaxe separada de templates.

Quando uma função aceita anytype, o compilador gera uma versão especializada para cada combinação de tipos usada. Isso se aproxima de templates em C++, com sintaxe mais enxuta e erros que normalmente apontam para o uso concreto do valor.

Por que anytype importa

  1. Genéricos simples: cria funções que aceitam vários tipos sem boilerplate de <T>.
  2. Duck typing em comptime: o compilador verifica se o tipo realmente oferece as operações usadas.
  3. Zero overhead: cada especialização é compilada individualmente, sem vtable obrigatória.
  4. Composição: combina com @TypeOf e @typeInfo para introspecção e validação.

Exemplo prático

Função genérica com anytype

const std = @import("std");

fn dobrar(valor: anytype) @TypeOf(valor) {
    return valor * 2;
}

pub fn main() void {
    const a: u32 = dobrar(@as(u32, 21));
    const b: f64 = dobrar(@as(f64, 1.5));
    const c: i8 = dobrar(@as(i8, -10));

    std.debug.print("u32: {}\n", .{a}); // 42
    std.debug.print("f64: {d}\n", .{b}); // 3.0
    std.debug.print("i8: {}\n", .{c}); // -20
}

anytype com introspecção de tipo

const std = @import("std");

fn imprimir(valor: anytype) void {
    const T = @TypeOf(valor);
    const info = @typeInfo(T);

    switch (info) {
        .int, .comptime_int => std.debug.print("Inteiro: {}\n", .{valor}),
        .float, .comptime_float => std.debug.print("Float: {d}\n", .{valor}),
        .pointer => |ptr_info| {
            if (ptr_info.size == .slice and ptr_info.child == u8) {
                std.debug.print("String: {s}\n", .{valor});
            } else {
                std.debug.print("Ponteiro: {*}\n", .{valor});
            }
        },
        .bool => std.debug.print("Bool: {}\n", .{valor}),
        else => std.debug.print("Tipo: {s}\n", .{@typeName(T)}),
    }
}

pub fn main() void {
    imprimir(@as(u32, 42));
    imprimir(@as(f64, 3.14));
    imprimir(true);
    imprimir("Zig");
}

Writer genérico com anytype

const std = @import("std");

fn escreverSaudacao(writer: anytype, nome: []const u8) !void {
    try writer.print("Olá, {s}! Bem-vindo ao Zig.\n", .{nome});
}

pub fn main() !void {
    var buffer: [128]u8 = undefined;
    var stream = std.io.fixedBufferStream(&buffer);
    try escreverSaudacao(stream.writer(), "Brasil");

    std.debug.print("{s}", .{stream.getWritten()});
}

Esse padrão — aceitar writer: anytype — aparece com frequência na biblioteca padrão e em APIs que não querem acoplar a função a um writer concreto.

anytype vs comptime T: type

Aspectoanytypecomptime T: type
SintaxeImplícitaExplícita
Acesso ao tipoVia @TypeOf(param)Diretamente via T
Vários parâmetros do mesmo tipoCada um pode diferirForça o mesmo T
Uso típicoFunções curtas, writers, helpersContêineres e APIs com tipo nomeado

Regra prática: comece com anytype quando a assinatura fica mais clara sem nomear o tipo; mude para comptime T: type quando o tipo precisa ser reutilizado, documentado ou compartilhado entre campos e parâmetros.

Validando tipos com @compileError

Quando anytype recebe um tipo inadequado, o erro padrão pode apontar para uma linha interna pouco amigável. Valide cedo:

const std = @import("std");

fn somar(a: anytype, b: anytype) @TypeOf(a) {
    const T = @TypeOf(a);
    const info = @typeInfo(T);

    if (info != .int and info != .float and info != .comptime_int and info != .comptime_float) {
        @compileError("somar() requer tipo numérico, recebeu: " ++ @typeName(T));
    }

    return a + b;
}

pub fn main() void {
    std.debug.print("{}\n", .{somar(@as(u32, 10), @as(u32, 20))});
}

Esse padrão é comum na biblioteca padrão do Zig para produzir mensagens acionáveis.

Casos de uso típicos

  • Funções matemáticas: fn abs(x: anytype) @TypeOf(x) para tipos numéricos.
  • Writers genéricos: funções que aceitam qualquer valor com .print / .writeAll.
  • Logging e formatação: helpers que formatam valores arbitrários em comptime.
  • Wrappers: decorators que envolvem outro valor sem conhecer o tipo concreto.

Para o mecanismo mais amplo por trás disso, veja o guia de comptime em Zig e a página de reflexão com comptime.

Armadilhas comuns

  • Erros difíceis de ler: valide com @typeInfo e @compileError no início da função.
  • Dois anytype diferentes: dois parâmetros anytype podem receber tipos distintos; force igualdade com comptime T: type quando necessário.
  • Não é dinâmico: anytype não cria um objeto “qualquer” em runtime.
  • Tipo de retorno: use @TypeOf(param) quando o retorno deve acompanhar o argumento.
  • APIs de I/O em evolução: em Zig 0.16, writers e std.Io mudaram; ao copiar exemplos antigos com getStdOut().writer(), confira o guia de migração Writergate e as novidades do Zig 0.16.

Perguntas frequentes

O que é anytype em Zig?

anytype é o parâmetro cujo tipo o compilador infere na chamada. É a forma mais direta de escrever genéricos implícitos em Zig.

anytype é tipagem dinâmica?

Não. Cada chamada gera código especializado em comptime. Não há boxing nem dispatch dinâmico implícito.

Quando preferir comptime T: type?

Quando o tipo precisa de nome, aparece em vários parâmetros/campos ou faz parte da API pública de um contêiner genérico.

Como inspecionar o tipo inferido?

Use @TypeOf(valor) para obter o tipo e @typeInfo para ler a tagged union descritiva desse tipo.

Termos relacionados

  • Struct — tipos compostos e genéricos com comptime
  • Tagged Union — unions discriminadas usadas em introspecção
  • Sentinel — slices e arrays terminados por sentinela
  • usize — inteiro de tamanho nativo para índices e tamanhos

Tutoriais relacionados

Continue aprendendo Zig

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