@intFromEnum em Zig
O @intFromEnum extrai o valor inteiro subjacente (tag value) de um valor enum. Todo enum em Zig possui internamente um tipo inteiro que representa cada variante, e este builtin permite acessar esse valor numérico diretamente.
Sintaxe
@intFromEnum(valor: anytype) TagType
O que faz
O @intFromEnum recebe um valor de tipo enum e retorna o valor inteiro correspondente à tag daquela variante. Por padrão, os valores são atribuídos sequencialmente começando em zero, mas podem ser personalizados na declaração do enum.
Parâmetros
- valor (
anytype): Um valor de tipo enum. Deve ser uma instância de um tipo enum válido.
Valor de retorno
Retorna o valor inteiro da tag do enum. O tipo do inteiro retornado corresponde ao tipo de tag do enum (que pode ser especificado explicitamente ou inferido pelo compilador).
Exemplos práticos
Exemplo 1: Obtendo valores de enum padrão
const std = @import("std");
const Direcao = enum { norte, sul, leste, oeste };
test "valores padrão de enum" {
// Por padrão, enums são numerados sequencialmente a partir de 0
try std.testing.expect(@intFromEnum(Direcao.norte) == 0);
try std.testing.expect(@intFromEnum(Direcao.sul) == 1);
try std.testing.expect(@intFromEnum(Direcao.leste) == 2);
try std.testing.expect(@intFromEnum(Direcao.oeste) == 3);
}
Exemplo 2: Enum com valores personalizados
const std = @import("std");
const HttpStatus = enum(u16) {
ok = 200,
criado = 201,
nao_encontrado = 404,
erro_interno = 500,
nao_implementado = 501,
};
fn statusParaString(status: HttpStatus) []const u8 {
return switch (status) {
.ok => "OK",
.criado => "Criado",
.nao_encontrado => "Não Encontrado",
.erro_interno => "Erro Interno do Servidor",
.nao_implementado => "Não Implementado",
};
}
test "HTTP status codes" {
const status = HttpStatus.nao_encontrado;
const codigo: u16 = @intFromEnum(status);
try std.testing.expect(codigo == 404);
try std.testing.expectEqualStrings("Não Encontrado", statusParaString(status));
// Útil para serialização ou comunicação via rede
const ok_code: u16 = @intFromEnum(HttpStatus.ok);
try std.testing.expect(ok_code == 200);
}
Exemplo 3: Flags com enum e operações bit a bit
const std = @import("std");
const Permissao = enum(u8) {
leitura = 0b001,
escrita = 0b010,
execucao = 0b100,
};
fn temPermissao(mascara: u8, perm: Permissao) bool {
return (mascara & @intFromEnum(perm)) != 0;
}
fn combinarPermissoes(perms: []const Permissao) u8 {
var resultado: u8 = 0;
for (perms) |p| {
resultado |= @intFromEnum(p);
}
return resultado;
}
test "verificar permissões" {
const perms = [_]Permissao{ .leitura, .escrita };
const mascara = combinarPermissoes(&perms);
try std.testing.expect(mascara == 0b011);
try std.testing.expect(temPermissao(mascara, .leitura));
try std.testing.expect(temPermissao(mascara, .escrita));
try std.testing.expect(!temPermissao(mascara, .execucao));
}
Casos de uso comuns
- Serialização: Converter valores enum para inteiros para transmitir via rede, salvar em arquivo ou enviar para APIs C.
- Operações bit a bit: Usar valores de enum como flags combinados com operações OR, AND, XOR.
- Indexação de arrays: Usar o valor do enum como índice em um array de lookup.
- Protocolos de comunicação: Converter enums para códigos numéricos de protocolo (como HTTP status codes).
- Interoperabilidade com C: Converter enums Zig para valores inteiros esperados por funções C.
const NivelLog = enum(u8) { debug = 0, info = 1, warn = 2, err = 3 };
var contadores: [4]u64 = .{ 0, 0, 0, 0 };
fn incrementarContador(nivel: NivelLog) void {
contadores[@intFromEnum(nivel)] += 1;
}
Tipo de tag do enum
O tipo inteiro usado internamente pelo enum pode ser especificado explicitamente ou inferido pelo compilador. Quando não especificado, o Zig escolhe o menor tipo inteiro capaz de representar todas as variantes:
const Pequeno = enum { a, b, c }; // tipo de tag inferido: u2 (cabe 0, 1, 2)
const Grande = enum(u32) { x = 0, y = 1_000_000 }; // tipo explícito: u32
const tag_pequeno = @intFromEnum(Pequeno.b); // tipo: u2
const tag_grande = @intFromEnum(Grande.y); // tipo: u32
Para verificar o tipo de tag de um enum em comptime, use @typeInfo:
const TagType = @typeInfo(Pequeno).@"enum".tag_type; // u2
Comparação com C equivalente
Em C, enums são implicitamente inteiros, e a conversão ocorre automaticamente — o que pode esconder bugs:
typedef enum { OK = 200, NAO_ENCONTRADO = 404 } Status;
int codigo = NAO_ENCONTRADO; // conversão implícita, sem aviso
Em Zig, a conversão deve ser explícita, deixando a intenção clara:
const Status = enum(u16) { ok = 200, nao_encontrado = 404 };
const codigo: u16 = @intFromEnum(.nao_encontrado); // explícito e seguro
Além disso, em Zig o tipo de tag é sempre bem definido e consistente entre plataformas, enquanto em C o tamanho de um enum pode variar entre compiladores e plataformas.
Erros comuns
Erro 1: Assumir que todos os enums começam em zero.
const Status = enum(u16) { ok = 200, erro = 500 };
// @intFromEnum(.ok) == 200, não 0!
// Não use o resultado como índice de array diretamente.
Erro 2: Armazenar o valor inteiro em um tipo menor que o tipo de tag.
const Grande = enum(u32) { max = 1_000_000 };
const val: u8 = @intFromEnum(Grande.max); // Overflow silencioso ou erro de compilação!
Sempre armazene o resultado em um tipo compatível com o tipo de tag do enum.
Perguntas Frequentes
P: Posso usar @intFromEnum com enums não exaustivos (com _)?
Sim. Enums não exaustivos aceitam valores arbitrários do tipo de tag, e @intFromEnum retorna o valor inteiro correspondente, seja ele uma variante nomeada ou não.
P: @intFromEnum funciona em comptime?
Sim. Se o valor do enum for conhecido em tempo de compilação, o resultado também é comptime. Isso é útil para calcular tamanhos de arrays e outros valores comptime baseados em variantes de enum.
P: Como obter o número total de variantes de um enum?
Use @typeInfo para acessar a lista de campos do enum:
const num_variantes = @typeInfo(DiaSemana).@"enum".fields.len;
Builtins relacionados
- @enumFromInt — Operação inversa: cria enum a partir de inteiro
- @tagName — Obtém o nome da variante como string
- @intFromBool — Converte booleano para inteiro
- @typeInfo — Inspeciona a definição do enum