@intFromEnum em Zig — Referência e Exemplos

@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

  1. Serialização: Converter valores enum para inteiros para transmitir via rede, salvar em arquivo ou enviar para APIs C.
  2. Operações bit a bit: Usar valores de enum como flags combinados com operações OR, AND, XOR.
  3. Indexação de arrays: Usar o valor do enum como índice em um array de lookup.
  4. Protocolos de comunicação: Converter enums para códigos numéricos de protocolo (como HTTP status codes).
  5. 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

Tutoriais relacionados

Continue aprendendo Zig

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