@typeName em Zig
O @typeName é um builtin que retorna o nome de qualquer tipo como uma string legível. É extremamente útil para depuração, logging e geração de mensagens de erro em código genérico. Como opera em tempo de compilação, não há custo em tempo de execução para seu uso.
Sintaxe
@typeName(comptime T: type) *const [N:0]u8
O que faz
O @typeName converte um tipo Zig para sua representação textual como uma string de bytes terminada em sentinela nulo. O nome retornado é o nome totalmente qualificado do tipo, incluindo o módulo de origem quando aplicável. Para tipos anônimos (como closures ou structs literais), o compilador gera um nome descritivo.
Parâmetros
- T (
type, comptime): O tipo cujo nome será retornado. Pode ser qualquer tipo válido em Zig — primitivos, structs, enums, unions, ponteiros, arrays, tipos de função, etc.
Valor de retorno
Retorna um ponteiro para uma string de bytes constante terminada em sentinela zero (*const [N:0]u8), que pode ser usada diretamente como []const u8. O conteúdo é o nome textual do tipo.
Exemplos práticos
Exemplo 1: Nomes de tipos primitivos
const std = @import("std");
test "nomes de tipos primitivos" {
try std.testing.expectEqualStrings("i32", @typeName(i32));
try std.testing.expectEqualStrings("u8", @typeName(u8));
try std.testing.expectEqualStrings("f64", @typeName(f64));
try std.testing.expectEqualStrings("bool", @typeName(bool));
try std.testing.expectEqualStrings("void", @typeName(void));
}
Exemplo 2: Mensagens de erro genéricas
const std = @import("std");
fn processar(comptime T: type, valor: T) !void {
const info = @typeInfo(T);
switch (info) {
.int => {
std.debug.print("Processando inteiro do tipo {s}: {}\n", .{
@typeName(T),
valor,
});
},
.float => {
std.debug.print("Processando float do tipo {s}: {d}\n", .{
@typeName(T),
valor,
});
},
else => {
@compileError("Tipo não suportado: " ++ @typeName(T));
},
}
}
test "processar valores" {
try processar(i32, 42);
try processar(f64, 3.14);
// processar(bool, true); // Erro de compilação: "Tipo não suportado: bool"
}
Exemplo 3: Nomes de tipos compostos
const std = @import("std");
const Ponto = struct {
x: f32,
y: f32,
};
const Cor = enum { vermelho, verde, azul };
test "nomes de tipos compostos" {
// Structs incluem o caminho do módulo
std.debug.print("Struct: {s}\n", .{@typeName(Ponto)});
// Enums também
std.debug.print("Enum: {s}\n", .{@typeName(Cor)});
// Tipos compostos mostram estrutura
std.debug.print("Slice: {s}\n", .{@typeName([]const u8)});
std.debug.print("Ponteiro: {s}\n", .{@typeName(*Ponto)});
std.debug.print("Optional: {s}\n", .{@typeName(?i32)});
std.debug.print("Array: {s}\n", .{@typeName([5]u8)});
// Saída típica:
// Struct: type-name.Ponto
// Enum: type-name.Cor
// Slice: []const u8
// Ponteiro: *type-name.Ponto
// Optional: ?i32
// Array: [5]u8
}
Casos de uso comuns
Depuração de código genérico: Quando uma função genérica não se comporta como esperado,
@typeNameajuda a identificar exatamente qual tipo está sendo processado.Mensagens de erro em comptime: Combinar
@typeNamecom@compileErrorpara gerar mensagens de erro claras quando um tipo inválido é passado a uma função genérica.Logging e telemetria: Incluir o nome do tipo em mensagens de log para rastreabilidade.
Serialização: Usar o nome do tipo como chave em formatos de serialização que precisam preservar informações de tipo.
Geração de documentação: Ferramentas que geram documentação automaticamente podem usar
@typeNamepara descrever tipos.
Builtins relacionados
- @typeInfo — Obtém informações detalhadas sobre um tipo
- @TypeOf — Obtém o tipo de uma expressão
- @errorName — Obtém o nome de um erro como string
- @tagName — Obtém o nome do campo ativo de uma tagged union
- @compileError — Gera erro de compilação com mensagem