@enumFromInt em Zig
O @enumFromInt cria um valor enum a partir de um valor inteiro. É a operação inversa de @intFromEnum. Este builtin é especialmente útil ao deserializar dados, processar protocolos de rede ou interagir com código C que usa constantes inteiras no lugar de enums.
Sintaxe
@enumFromInt(valor: IntType) EnumType
O tipo enum de retorno é inferido pelo contexto.
O que faz
O @enumFromInt recebe um valor inteiro e o converte para a variante correspondente de um tipo enum. Se o valor inteiro não corresponder a nenhuma variante definida no enum, o comportamento é ilegal e será detectado como erro em modo debug (safety-checked).
Parâmetros
- valor (
IntType): O valor inteiro a ser convertido para enum. O tipo deve ser compatível com o tipo de tag do enum de destino.
Valor de retorno
Retorna o valor enum correspondente ao inteiro fornecido.
Exemplos práticos
Exemplo 1: Conversão básica
const std = @import("std");
const Cor = enum { vermelho, verde, azul };
test "conversão inteiro para enum" {
const cor: Cor = @enumFromInt(0);
try std.testing.expect(cor == .vermelho);
const outra: Cor = @enumFromInt(2);
try std.testing.expect(outra == .azul);
}
Exemplo 2: Deserialização de protocolo
const std = @import("std");
const TipoMensagem = enum(u8) {
ping = 1,
pong = 2,
dados = 3,
erro = 4,
desconexao = 5,
};
const Mensagem = struct {
tipo: TipoMensagem,
payload: []const u8,
};
fn parsearMensagem(buffer: []const u8) !Mensagem {
if (buffer.len < 2) return error.MensagemMuitoCurta;
const byte_tipo = buffer[0];
if (byte_tipo < 1 or byte_tipo > 5) return error.TipoInvalido;
const tipo: TipoMensagem = @enumFromInt(byte_tipo);
const tamanho_payload = buffer[1];
if (buffer.len < 2 + tamanho_payload) return error.PayloadIncompleto;
return .{
.tipo = tipo,
.payload = buffer[2 .. 2 + tamanho_payload],
};
}
test "parsear mensagem" {
const buffer = [_]u8{ 1, 3, 'a', 'b', 'c' };
const msg = try parsearMensagem(&buffer);
try std.testing.expect(msg.tipo == .ping);
try std.testing.expectEqualStrings("abc", msg.payload);
}
Exemplo 3: Iteração sobre todos os valores de um enum
const std = @import("std");
const DiaSemana = enum(u8) {
segunda = 0,
terca = 1,
quarta = 2,
quinta = 3,
sexta = 4,
sabado = 5,
domingo = 6,
};
fn nomeDodia(dia: DiaSemana) []const u8 {
return switch (dia) {
.segunda => "Segunda-feira",
.terca => "Terça-feira",
.quarta => "Quarta-feira",
.quinta => "Quinta-feira",
.sexta => "Sexta-feira",
.sabado => "Sábado",
.domingo => "Domingo",
};
}
test "iterar sobre dias da semana" {
// Usar @enumFromInt para iterar por todos os valores possíveis
var i: u8 = 0;
while (i <= 6) : (i += 1) {
const dia: DiaSemana = @enumFromInt(i);
const nome = nomeDodia(dia);
std.debug.print("Dia {}: {s}\n", .{ i, nome });
}
}
Casos de uso comuns
- Deserialização: Converter bytes recebidos de rede, arquivo ou API para valores enum tipados.
- Interoperabilidade com C: Converter constantes inteiras retornadas por funções C para enums Zig mais seguros.
- Iteração: Percorrer todos os valores possíveis de um enum usando um loop numérico.
- Tabelas de lookup: Converter índices de array para valores enum correspondentes.
- Protocolos binários: Parsear cabeçalhos de protocolo que usam códigos numéricos.
Cuidados importantes
- Se o valor inteiro não corresponder a nenhuma variante válida do enum, o comportamento é ilegal. Em modo debug, isso causa um panic. Em modo release, o comportamento pode ser indefinido.
- Sempre valide o valor inteiro antes de chamar
@enumFromIntquando os dados vêm de fontes externas não confiáveis.
Comparação com C equivalente
Em C, a conversão de inteiro para enum é implícita e completamente insegura:
typedef enum { VERMELHO = 0, VERDE = 1, AZUL = 2 } Cor;
// C aceita qualquer valor, sem verificação
Cor cor = (Cor)99; // Comportamento indefinido silencioso!
Em Zig, a conversão é explícita e verificada em modo debug:
const Cor = enum { vermelho, verde, azul };
// Isso causará panic em debug se 99 não for um valor válido:
const cor: Cor = @enumFromInt(99); // panic: invalid enum value
A abordagem do Zig força o programador a validar o dado antes da conversão, eliminando uma categoria inteira de bugs silenciosos presentes em código C.
Erros comuns
Erro 1: Não validar dados externos antes da conversão.
// ERRADO — pode causar panic se byte_tipo for inválido
const tipo: TipoMensagem = @enumFromInt(byte_tipo);
// CORRETO — validar primeiro
if (byte_tipo < 1 or byte_tipo > 5) return error.TipoInvalido;
const tipo: TipoMensagem = @enumFromInt(byte_tipo);
Erro 2: Esquecer que enums com valores personalizados não são contíguos.
const Status = enum(u16) { ok = 200, nao_encontrado = 404, erro = 500 };
// Isso vai causar panic — 201 não é um valor válido!
const s: Status = @enumFromInt(201);
Erro 3: Confundir a ordem das variantes com o valor inteiro.
Se um enum não tem valores explícitos, a atribuição é sequencial começando em zero. Mas ao adicionar ou reordenar variantes, os valores mudam — isso pode quebrar compatibilidade de protocolos binários. Prefira sempre declarar os valores explicitamente quando a ordem importa.
Perguntas Frequentes
P: É possível usar @enumFromInt em tempo de compilação (comptime)?
Sim. Se o valor inteiro for conhecido em comptime, a conversão também ocorre em comptime, e qualquer valor inválido resultará em erro de compilação em vez de panic em runtime.
const cor: Cor = comptime @enumFromInt(0); // OK — resolvido em comptime
P: Como verificar com segurança se um inteiro é um valor válido de enum antes de converter?
Use std.meta.intToEnum da biblioteca padrão, que retorna um error union em vez de causar panic:
const std = @import("std");
const cor = std.meta.intToEnum(Cor, byte_recebido) catch return error.ValorInvalido;
P: @enumFromInt funciona com enums não exaustivos (_)?
Sim. Enums não exaustivos (declarados com _ como última variante) aceitam qualquer valor inteiro do tipo de tag, então @enumFromInt sempre terá sucesso com qualquer valor dentro do intervalo do tipo inteiro.
Builtins relacionados
- @intFromEnum — Operação inversa: obtém inteiro do enum
- @tagName — Obtém o nome da variante como string
- @typeInfo — Inspeciona as variantes de um enum
- @errorName — Obtém o nome de um erro