Erro E0533 do Rust: expected unit struct, unit variant or constant, found struct variant
O E0533 quer dizer: você escreveu um nome como Shape::Circle sozinho, mas nesse lugar esse nome precisa de mais do que só o nome. Na maioria das vezes é uma variante de enum com campos nomeados (Circle { radius: f64 }) escrita sem as suas { }, seja num braço de match, seja ao criar um valor. Menos vezes é uma função ou um método escrito onde só cabe um valor fixo. Os dois casos se corrigem rápido depois que você entende o que o rustc está pedindo. (Esta página faz parte de Erros do compilador Rust explicados.)
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0533]: expected unit struct, unit variant or constant, found struct variant `Shape::Circle` --> src/main.rs:8:9 |8 | Shape::Circle => "círculo", // ❌ `Circle` tem um campo | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant |help: the struct variant's field is being ignored |8 | Shape::Circle { radius: _ } => "círculo", // ❌ `Circle` tem um campo | +++++++++++++Em português: “era esperada uma unit struct, uma variante unitária ou uma constante, mas foi encontrada a variante de struct Shape::Circle”. O rótulo repete que ela não é nenhuma dessas três coisas, e a ajuda diz que o campo da variante de struct está sendo ignorado, mostrando como escrever isso.
Este é o programa que gera o erro:
enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle => "círculo", // ❌ `Circle` tem um campo Shape::Square { .. } => "quadrado", }}
fn main() { println!("{}", name(&Shape::Square { side: 2.0 }));}O que significa
Seção intitulada “O que significa”O ^^^ aponta para Shape::Circle, e a primeira linha explica o que era permitido ali: um padrão que é só um nome precisa ser uma de três coisas:
- uma unit struct (struct unitária, sem campos), como
struct Empty; - uma variante unitária, uma variante sem dados, como
Shape::EmptyouNone - uma constante, como
const MAX: u32 = 100;
Shape::Circle não é nenhuma dessas. É uma variante de struct: ela carrega um radius. Um Shape::Circle sozinho casaria com “um círculo”, mas não diria nada sobre o campo dele, e o Rust quer que o formato do padrão seja igual ao formato da variante. A linha help: mostra a correção: acrescente as chaves.
O segundo tipo de E0533 diz expected value, found struct variant (era esperado um valor, foi encontrada uma variante de struct). É a mesma confusão, só que ao criar um valor, normalmente escrito com parênteses, como Shape::Circle(2.0).
É como um formulário de encomenda com um campo que diz “Tamanho: P, M ou G”, e você escreveu “Personalizado”. Personalizado é uma opção que existe, mas precisa das medidas preenchidas ao lado.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”As variantes de um enum vêm em três formatos, e cada um tem o seu jeito de escrever, tanto para criar quanto para usar no match (veja Enums podem guardar dados):
| Variante | Para criar | Para casar no match |
|---|---|---|
Unitária: Empty |
Shape::Empty |
Shape::Empty |
De tupla: Point(f64, f64) |
Shape::Point(1.0, 2.0) |
Shape::Point(x, y) ou Shape::Point(..) |
De struct: Circle { radius: f64 } |
Shape::Circle { radius: 2.0 } |
Shape::Circle { radius } ou Shape::Circle { .. } |
Manter os formatos rígidos faz com que um padrão sempre se pareça com aquilo que ele casa, então você lê um match e sabe exatamente quais dados cada braço tem. Também faz com que, quando uma variante muda de formato, por exemplo quando Empty ganha um campo, todo lugar que usa o formato antigo seja apontado, em vez de fazer a coisa errada em silêncio.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Acrescente { .. } ou os campos ao padrão
Seção intitulada “Correção 1: Acrescente { .. } ou os campos ao padrão”Escolha esta quando o erro aponta para um braço de match, if let ou matches! e diz found struct variant. Escreva { .. } se você não precisa dos campos, ou cite os campos se precisa. A sugestão do rustc, { radius: _ }, também funciona, e { .. } é o jeito mais curto de dizer a mesma coisa.
enum Shape { Circle { radius: f64 }, Square { side: f64 }, Empty,}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle { .. } => "círculo", // ✅ "um círculo, seja qual for o raio" Shape::Square { .. } => "quadrado", Shape::Empty => "nada", // uma variante unitária: não precisa de chaves }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle { radius } => 3.14 * radius * radius, // ✅ campos citados porque precisamos deles Shape::Square { side } => side * side, Shape::Empty => 0.0, }}
fn main() { let shapes = [Shape::Circle { radius: 1.0 }, Shape::Square { side: 3.0 }, Shape::Empty]; for shape in &shapes { println!("{}: {:.2}", name(shape), area(shape)); } let circles = shapes.iter().filter(|s| matches!(s, Shape::Circle { .. })).count(); println!("{} círculo(s)", circles);}Saída:
círculo: 3.14quadrado: 9.00nada: 0.001 círculo(s){ .. } funciona para qualquer variante de struct, não importa quantos campos ela tenha. Para variantes de tupla, a mesma ideia se escreve (..). Veja Ignorando partes com _ e ...
Correção 2: Crie o valor com chaves e nomes de campos
Seção intitulada “Correção 2: Crie o valor com chaves e nomes de campos”Escolha esta quando a mensagem diz expected value, found struct variant. Você está criando uma variante de struct como se fosse uma variante de tupla (ou sem nenhum campo):
error[E0533]: expected value, found struct variant `Shape::Circle` --> src/main.rs:8:17 |8 | let shape = Shape::Circle(2.0); // ❌ `Circle` tem um campo nomeado | ^^^^^^^^^^^^^ not a value |help: you might have meant to create a new value of the struct |8 - let shape = Shape::Circle(2.0); // ❌ `Circle` tem um campo nomeado8 + let shape = Shape::Circle { radius: /* value */ }; // ❌ `Circle` tem um campo nomeado |O rótulo diz “não é um valor”, e a ajuda diz que talvez você quisesse criar um novo valor da struct, mostrando a linha com chaves.
O programa por trás dele:
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn main() { let shape = Shape::Circle(2.0); // ❌ `Circle` tem um campo nomeado println!("{:?}", shape);}O /* value */ na sugestão é um lugar reservado para o seu valor. Os campos de uma variante de struct são preenchidos pelo nome, dentro de chaves:
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
impl Shape { // um construtor curto, se você quiser escrever `Shape::circle(2.0)` fn circle(radius: f64) -> Shape { Shape::Circle { radius } }}
fn main() { let a = Shape::Circle { radius: 2.0 }; // ✅ chaves e o nome do campo let b = Shape::Square { side: 1.5 }; let c = Shape::circle(0.5); println!("{:?}", a); println!("{:?}", b); println!("{:?}", c);}Saída:
Circle { radius: 2.0 }Square { side: 1.5 }Circle { radius: 0.5 }Se você prefere escrever Shape::Circle(2.0), mude a definição para uma variante de tupla: Circle(f64). É uma boa escolha quando há um único campo óbvio; campos nomeados ficam mais claros quando há vários.
Correção 3: Use uma constante ou um match guard em vez de uma função
Seção intitulada “Correção 3: Use uma constante ou um match guard em vez de uma função”Escolha esta quando a mensagem diz found associated function (foi encontrada uma função associada). Ela também aparece para métodos, como String::len. Um padrão precisa ser um valor conhecido na hora de compilar. Uma chamada de função não é, então o nome de uma função não pode ser usado como padrão:
error[E0533]: expected unit struct, unit variant or constant, found associated function `Limits::max_users` --> src/main.rs:12:9 |12 | Limits::max_users => "lotado", // ❌ uma função não pode ser um padrão | ^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constantO rustc diz que esperava uma unit struct, uma variante unitária ou uma constante, e encontrou a função associada Limits::max_users.
O programa por trás dele:
struct Limits;
impl Limits { fn max_users() -> u32 { 100 }}
fn status(users: u32) -> &'static str { match users { 0 => "vazio", Limits::max_users => "lotado", // ❌ uma função não pode ser um padrão _ => "aberto", }}
fn main() { println!("{}", status(100));}Se o valor nunca muda, transforme-o num const. Constantes podem ser padrões. Se ele precisa ser calculado, mantenha a função e compare num match guard com if:
struct Limits;
impl Limits { const MAX_USERS: u32 = 100; // uma constante pode ser usada como padrão
fn max_rooms(premium: bool) -> u32 { if premium { 20 } else { 5 } }}
fn status(users: u32) -> &'static str { match users { 0 => "vazio", Limits::MAX_USERS => "lotado", // ✅ uma constante _ => "aberto", }}
fn rooms_status(rooms: u32, premium: bool) -> &'static str { match rooms { n if n >= Limits::max_rooms(premium) => "não dá para criar mais salas", // ✅ chame no guard _ => "você pode criar uma sala", }}
fn main() { println!("{}", status(0)); println!("{}", status(100)); println!("{}", status(42)); println!("{}", rooms_status(5, false)); println!("{}", rooms_status(5, true));}Saída:
vaziolotadoabertonão dá para criar mais salasvocê pode criar uma salaOs match guards são explicados em Match guards: adicionando um if.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Depois que uma variante unitária ganha campos. Status::Done era uma variante unitária, e você mudou para Done { at: u64 }. Todo braço Status::Done => e todo let s = Status::Done; agora dão E0533. Correção: Status::Done { .. } => nos padrões, e Status::Done { at: 0 } (com um valor de verdade) onde você cria o valor.
Vindo de outra linguagem. Em Java ou TypeScript você talvez escreva case Circle: para conferir só o tipo de um valor. Em Rust, escreva Shape::Circle { .. } =>, ou matches!(shape, Shape::Circle { .. }) para ter um bool rápido.
A versão para variantes de tupla. Para uma variante de tupla como Circle(f64), um braço Shape::Circle => sozinho dá outro código, o E0532, com a mesma primeira linha “expected unit struct, unit variant or constant, found tuple variant Shape::Circle” (foi encontrada uma variante de tupla). A correção é Shape::Circle(_) ou Shape::Circle(..). E parênteses numa variante de struct dentro de um padrão, como Shape::Circle(r) => para Circle { radius: f64 }, dão o E0164, “expected tuple struct or tuple variant, found struct variant” (era esperada uma tuple struct ou variante de tupla, foi encontrada uma variante de struct). Correção: Shape::Circle { radius: r } =>.
Erros relacionados
Seção intitulada “Erros relacionados”- E0559: variant has no field named x: as chaves estão certas, mas um nome de campo dentro delas está errado.
- E0026: struct or variant does not have a field named x: um nome de campo errado dentro das chaves de um padrão.
- E0027: pattern does not mention field x: chaves num padrão que deixam campos de fora; acrescente
... - E0004: non-exhaustive patterns: depois de corrigir os braços, o
matchainda precisa cobrir todas as variantes. E0532: expected unit struct, unit variant or constant, found tuple variant: a versão para variantes de tupla (veja acima).- Todos os erros do compilador explicados
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Para enum Shape { Circle { radius: f64 } }, qual braço de match compila?
2. let s = Shape::Circle(2.0); dá "expected value, found struct variant". Qual é a correção?
3. Qual destes pode ser usado sozinho como padrão num match?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0533 — Rust error codes index (em inglês): a explicação oficial deste erro.
- Pattern Syntax — The Rust Book (em inglês): como desestruturar enums, ignorar valores com
..e usar match guards. - Destructuring enums — Rust by Example (em inglês): variantes unitárias, de tupla e de struct casadas lado a lado.
- E0532 — Rust error codes index (em inglês): a página oficial da versão deste engano para variantes de tupla.
- Patterns — The Rust Reference (em inglês): quais caminhos podem ser usados como padrões, e as regras dos padrões de struct e de tuple struct.