Enums
Enums definem um tipo que é uma de várias variantes. As variantes podem conter dados, tornando os enums ideais para máquinas de estado e modelos de erro.
Receita
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
}
fn handle(msg: Message) {
match msg {
Message::Quit => println!("quit"),
Message::Move { x, y } => println!("move {x},{y}"),
Message::Write(text) => println!("{text}"),
}
}
fn main() {
handle(Message::Write("hi".into()));
}Quando usar isso: Modelar estados mutuamente exclusivos, erros, comandos e nós AST.
Exemplo em Funcionamento
enum Traffic {
Red,
Yellow,
Green,
}
impl Traffic {
fn next(self) -> Self {
match self {
Traffic::Red => Traffic::Green,
Traffic::Green => Traffic::Yellow,
Traffic::Yellow => Traffic::Red,
}
}
}
fn main() {
let t = Traffic::Red.next();
println!("{:?}", std::mem::discriminant(&t));
}O que isso demonstra:
- Variantes de unidade como enums C
- Métodos em enums via
impl - Consumindo
selfemnextpara API de transição de estado matchpara tratamento exaustivo
Mergulho Profundo
Formas de Variantes
enum E {
Unit,
Tuple(i32, String),
Struct { id: u64 },
}Layout de Memória
Rust otimiza enums de nicho (por exemplo, Option<&T> tem o mesmo tamanho que &T). Nem todos os enums têm o mesmo tamanho da maior variante devido a otimizações.
Option e Result
enum Option<T> { None, Some(T) }
enum Result<T, E> { Ok(T), Err(E) }Veja a página dedicada para uso idiomático.
Armadilhas
matchnão exaustivo - Nova variante quebra o código downstream. Correção: Trate como um evento de semântica de API; use#[non_exhaustive]para extensibilidade.- Inchaço de variante grande - O tamanho do enum é pelo menos o da maior variante (antes da otimização). Correção: Use
Boxpara payload grande:Large(Box<Data>). - Cheiro de enum booleano -
enum Flag { Yes, No }é pior queboola menos que mais estados estejam por vir. Correção: Useboolaté que as variantes se multipliquem. - Derivar
Eqem payload float - Não disponível. Correção: Use representação inteira ou eviteEq. - Enum público com invariantes internas - Chamadores constroem combinações inválidas. Correção: Campos privados com construtores que validam o estado.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
Struct + flag bool | Apenas dois estados | Muitas transições ou payloads tipados |
| Objetos de trait | Conjunto aberto de tipos | Conjunto fechado - enum é mais rápido |
| Códigos inteiros | Interoperação FFI/C | Modelagem segura de domínio Rust |
crate bitflags | Muitas flags booleanas compactadas | Variantes semânticas importam |
FAQs
Variantes de enum podem conter tipos diferentes?
Sim. Cada variante define sua própria forma de payload.
Qual o tamanho de um enum?
Pelo menos o da maior variante; otimizações de nicho podem encolher alguns (por exemplo, Option).
Posso implementar traits em enums?
Sim, com impl Trait for MyEnum.
O que é `#[non_exhaustive]`?
Crates externas não podem fazer match exaustivo - evolução de enum compatível com versões futuras.
Enum vs hierarquia de trait selada?
Enum: conjunto fechado conhecido. Trait: implementações extensíveis entre crates.
Variantes podem ser genéricas?
Enums não podem ser genéricos por variante, mas o enum em si pode ser no estilo enum E<T> { Some(T), None } - use Option.
Otimização de ponteiro nulo?
Option<NonNull<T>> e similares usam valores de nicho para None.
Representação estilo C?
#[repr(C)] para controle de layout FFI - veja a seção Unsafe/FFI.
Nomeando variantes?
PascalCase para variantes, SCREAMING_SNAKE para o nome do enum não é usado - o enum também é PascalCase.
Teste exaustivo?
Adicione uma variante -> o compilador lista todos os locais de match para atualizar - recurso, não bug.
Relacionados
- Pattern Matching com match - Profundidade do
match - Option & Result como Enums - enums principais
- Enums para Máquinas de Estado - transições
- Derivando Traits -
#[derive(...)]
Versões da Pilha: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.