Pular para o conteúdo

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.)

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 ^^^ 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::Empty ou None
  • 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.

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.

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.14
quadrado: 9.00
nada: 0.00
1 círculo(s)
▶ Experimente você mesmo

{ .. } 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 nomeado
8 + 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 }
▶ Experimente você mesmo

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 constant

O 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:

vazio
lotado
aberto
não dá para criar mais salas
você pode criar uma sala
▶ Experimente você mesmo

Os match guards são explicados em Match guards: adicionando um if.

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 } =>.

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