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
| Pergunta | Resposta 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ícita | comptime T: type |
| Uso clássico | Writers, 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
- Genéricos simples: cria funções que aceitam vários tipos sem boilerplate de
<T>. - Duck typing em comptime: o compilador verifica se o tipo realmente oferece as operações usadas.
- Zero overhead: cada especialização é compilada individualmente, sem vtable obrigatória.
- Composição: combina com
@TypeOfe@typeInfopara 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
| Aspecto | anytype | comptime T: type |
|---|---|---|
| Sintaxe | Implícita | Explícita |
| Acesso ao tipo | Via @TypeOf(param) | Diretamente via T |
| Vários parâmetros do mesmo tipo | Cada um pode diferir | Força o mesmo T |
| Uso típico | Funções curtas, writers, helpers | Contê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
@typeInfoe@compileErrorno início da função. - Dois
anytypediferentes: dois parâmetrosanytypepodem receber tipos distintos; force igualdade comcomptime T: typequando necessário. - Não é dinâmico:
anytypenã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.Iomudaram; ao copiar exemplos antigos comgetStdOut().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