anytype em Zig — O que é e Como Usar

anytype em Zig — O que é e Como Usar

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, substituindo a necessidade de sintaxes como <T> de outras linguagens.

Quando uma função aceita anytype, o compilador gera uma versão especializada para cada combinação de tipos usada. Isso é semelhante a templates em C++, mas com uma sintaxe mais simples e mensagens de erro mais claras.

Por que anytype Importa

  1. Genéricos simples: Cria funções que aceitam qualquer tipo sem boilerplate.
  2. Duck typing em comptime: O compilador verifica se o tipo suporta as operações usadas na função.
  3. Zero overhead: Cada especialização é compilada individualmente, sem indireção.
  4. Composição: Combina com @TypeOf e @typeInfo para introspecção poderosa.

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 => std.debug.print("Inteiro: {}\n", .{valor}),
        .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);
}

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 {
    const stdout = std.io.getStdOut().writer();
    try escreverSaudacao(stdout, "Brasil");

    // Funciona com qualquer writer — arquivo, buffer, etc.
    var buffer: [256]u8 = undefined;
    var stream = std.io.fixedBufferStream(&buffer);
    try escreverSaudacao(stream.writer(), "Mundo");
}

anytype vs comptime T: type

Aspectoanytypecomptime T: type
SintaxeImplícitaExplícita
Acesso ao tipoVia @TypeOf(param)Diretamente via T
Múltiplos parâmetros do mesmo tipoCada um pode ser diferenteForça o mesmo tipo T
Uso típicoFunções simples, writersContêineres, funções com tipo explícito

Armadilhas Comuns

  • Mensagens de erro: Quando anytype recebe um tipo que não suporta as operações da função, o erro pode ser confuso. Adicione @compileError para mensagens claras.
  • Múltiplos anytype: Dois parâmetros anytype podem receber tipos diferentes. Se precisar forçar o mesmo tipo, use comptime T: type.
  • Não é tipagem dinâmica: anytype é resolvido em comptime. Não existe dispatch dinâmico — cada uso gera código especializado.
  • Tipo de retorno: Use @TypeOf(param) no tipo de retorno para que ele corresponda ao tipo do argumento.

Termos Relacionados

Tutoriais Relacionados

Continue aprendendo Zig

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