Pular para o conteúdo

Erro E0532 do Rust: expected unit struct, unit variant or constant, found tuple variant

O E0532 quer dizer: o formato do seu padrão não bate com o formato daquilo que você citou. O caso clássico é um braço de match como Shape::Circle => para uma variante que guarda dados, Circle(f64). O Rust quer os parênteses: Shape::Circle(_). O erro contrário recebe o mesmo código, com a outra mensagem, “expected tuple struct or tuple variant”: parênteses em algo que não tem dados entre parênteses, como Status::Active(). As duas coisas se corrigem numa linha. (Esta página faz parte de Erros do compilador Rust explicados.)

error[E0532]: expected unit struct, unit variant or constant, found tuple variant `Shape::Circle`
--> src/main.rs:8:9
|
2 | Circle(f64),
| ----------- `Shape::Circle` defined here
...
8 | Shape::Circle => "circle", // ❌ `Circle` holds a value
| ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Shape::Circle(_)`

Em português: “era esperada uma unit struct, uma variante unitária ou uma constante, mas foi encontrada a variante de tupla Shape::Circle”. A ajuda sugere usar a sintaxe de padrão de variante de tupla: Shape::Circle(_).

Este é o programa que gera o erro:

enum Shape {
Circle(f64),
Square(f64),
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle => "circle", // ❌ `Circle` holds a value
Shape::Square(_) => "square",
}
}
fn main() {
println!("{}", name(&Shape::Circle(1.0)));
}

(O comentário // ❌ `Circle` holds a value quer dizer “Circle guarda um valor”. Ele fica em inglês porque aparece na saída do compilador.)

O ^^^ aponta para Shape::Circle na linha 8, e o --- na linha 2 mostra como ela foi definida: Circle(f64), uma variante de tupla que carrega um f64. Um padrão que é só um nome, sem nada depois, 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 LIMIT: u32 = 100;

Shape::Circle não é nenhuma dessas. A linha de ajuda já traz a correção: Shape::Circle(_), ou seja, “um círculo, seja qual for o valor dele”.

A outra mensagem do E0532 é o espelho desta: expected tuple struct or tuple variant, found unit variant `Status::Active` (era esperada uma tuple struct ou uma variante de tupla, foi encontrada a variante unitária Status::Active), ou então found struct ou found constant. Nesse caso, foi você que escreveu parênteses depois de um nome, e aquilo que você citou não recebe valores entre parênteses.

É como um formulário que pede “Bicho: cachorro (nome: ____)”. Escrever só “cachorro” deixa o campo do nome vazio, e escrever “peixe (nome: Bolha)” onde o formulário diz só “peixe”, sem campo nenhum, inventa um campo que não existe.

Toda struct e toda variante de enum tem um de três formatos, e você escreve do mesmo jeito quando cria o valor e quando faz match nele (veja Enums podem guardar dados):

Tipo Para criar Para casar no match
Unitária: Empty Shape::Empty Shape::Empty
De tupla: Circle(f64) Shape::Circle(1.0) Shape::Circle(r) ou Shape::Circle(..)
De struct: Rect { w: f64, h: f64 } Shape::Rect { w: 2.0, h: 3.0 } Shape::Rect { w, h } ou Shape::Rect { .. }

Como os formatos são rígidos, um padrão sempre se parece com o valor que ele casa, e você lê um match e vê quais dados cada braço tem. Isso também ajuda quando você muda um tipo: se Empty mais tarde ganhar um valor e virar Empty(u32), todo braço antigo Shape::Empty é apontado, em vez de passar a casar com outra coisa em silêncio.

Correção 1: Acrescente (_), (..) ou nomes para os valores

Seção intitulada “Correção 1: Acrescente (_), (..) ou nomes para os valores”

Escolha esta quando a mensagem diz found tuple variant ou found tuple struct, que é o E0532 mais comum. Use _ para cada valor de que você não precisa, .. para pular todos de uma vez, ou um nome quando você quer usar o valor:

enum Shape {
Circle(f64),
Rect(f64, f64),
Empty,
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle(_) => "círculo", // ✅ um campo, ignorado
Shape::Rect(..) => "retângulo", // ✅ qualquer número de campos, todos ignorados
Shape::Empty => "nada", // uma variante unitária: sem parênteses
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ dá nome ao campo porque precisamos dele
Shape::Rect(w, h) => w * h,
Shape::Empty => 0.0,
}
}
fn main() {
let shapes = [Shape::Circle(1.0), Shape::Rect(2.0, 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
retângulo: 6.00
nada: 0.00
1 círculo(s)
▶ Experimente você mesmo

O (..) é prático para variantes com vários valores, e continua funcionando se você acrescentar mais um depois. Veja Ignorando partes com _ e ...

Escolha esta quando a mensagem diz found unit variant ou found unit struct. A variante não guarda dados, então não há nada para colocar entre parênteses:

error[E0532]: expected tuple struct or tuple variant, found unit variant `Status::Active`
--> src/main.rs:8:9
|
2 | Active,
| ------ `Status::Active` defined here
...
8 | Status::Active() => "active", // ❌ `Active` holds no data
| ^^^^^^^^^^^^^^^^ help: use this syntax instead: `Status::Active`

O rustc mostra onde Active foi definida, sem parênteses, e sugere escrever só Status::Active.

O programa por trás dele:

enum Status {
Active,
Banned(String),
}
fn label(s: &Status) -> &'static str {
match s {
Status::Active() => "active", // ❌ `Active` holds no data
Status::Banned(_) => "banned",
}
}
fn main() {
println!("{}", label(&Status::Active));
}

Escreva só o nome, tanto no padrão quanto no lugar em que você cria o valor:

#[derive(Debug)]
enum Status {
Active,
Banned(String),
}
fn label(s: &Status) -> String {
match s {
Status::Active => String::from("ativo"), // ✅ variante unitária: sem ()
Status::Banned(reason) => format!("banido ({})", reason),
}
}
fn main() {
println!("{}", label(&Status::Active));
println!("{}", label(&Status::Banned(String::from("spam"))));
let s = Status::Active; // ✅ e sem () também na hora de criar
println!("{:?}", s);
}

Saída:

ativo
banido (spam)
Active
▶ Experimente você mesmo

Se a sua intenção era que a variante carregasse dados, mude a definição: por exemplo, Active(u64) para guardar o momento em que a conta ficou ativa. Aí Status::Active(_) é o padrão certo.

Correção 3: Use chaves para uma struct com campos nomeados

Seção intitulada “Correção 3: Use chaves para uma struct com campos nomeados”

Escolha esta quando a mensagem diz found struct. Uma struct com campos nomeados, struct Point { x: i32, y: i32 }, é desestruturada com chaves e os nomes dos campos, e não com parênteses:

error[E0532]: expected tuple struct or tuple variant, found struct `Point`
--> src/main.rs:8:9
|
1 | / struct Point {
2 | | x: i32,
3 | | y: i32,
4 | | }
| |_- `Point` defined here
...
8 | let Point(x, y) = p; // ❌ `Point` has named fields
| ^^^^^^^^^^^ help: use struct pattern syntax instead: `Point { x, y }`

O rustc mostra a definição de Point, com campos nomeados, e sugere a sintaxe de padrão de struct: Point { x, y }.

O programa por trás dele:

struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 3, y: 4 };
let Point(x, y) = p; // ❌ `Point` has named fields
println!("{} {}", x, y);
}

A sugestão do rustc, Point { x, y }, está certinha. Use campo: nome quando quiser outro nome de variável:

struct Point {
x: i32,
y: i32,
}
struct Meters(f64); // uma tuple struct: aqui os parênteses estão certos
fn main() {
let p = Point { x: 3, y: 4 };
let Point { x, y } = p; // ✅ chaves e os nomes dos campos
println!("x = {}, y = {}", x, y);
let q = Point { x: -1, y: 7 };
let Point { x: left, y: up } = q; // ✅ renomeia ao desestruturar
println!("esquerda = {}, cima = {}", left, up);
let Meters(m) = Meters(2.5); // ✅ tuple struct, padrão de tupla
println!("{} m", m);
}

Saída:

x = 3, y = 4
esquerda = -1, cima = 7
2.5 m
▶ Experimente você mesmo

Para uma variante de enum com campos nomeados, Shape::Rect(w, h) para Rect { w: f64, h: f64 }, o mesmo erro dá outro código, o E0164. A correção é a mesma: chaves.

Correção 4: Use uma constante ou um match guard em vez de chamar uma função

Seção intitulada “Correção 4: Use uma constante ou um match guard em vez de chamar uma função”

Escolha esta quando a mensagem diz expected a pattern, found a function call (era esperado um padrão, foi encontrada uma chamada de função). Um padrão precisa ser conhecido em tempo de compilação, e uma chamada de função não é:

error[E0532]: expected a pattern, found a function call
--> src/main.rs:7:14
|
7 | Some(limit()) => "full", // ❌ a function call can't be a pattern
| ^^^^^ not a tuple struct or tuple variant
|
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>

A nota diz que chamadas de função não são permitidas em padrões, e o rótulo explica que limit não é uma tuple struct nem uma variante de tupla.

O programa por trás dele:

fn limit() -> u32 {
100
}
fn status(users: Option<u32>) -> &'static str {
match users {
Some(limit()) => "full", // ❌ a function call can't be a pattern
Some(_) => "open",
None => "closed",
}
}
fn main() {
println!("{}", status(Some(100)));
}

Se o valor nunca muda, transforme-o num const: constantes podem ser usadas dentro de padrões. Se ele precisa ser calculado, dê um nome ao valor e compare num match guard (um if no braço):

const LIMIT: u32 = 100; // uma constante pode ser usada dentro de um padrão
fn limit_for(premium: bool) -> u32 {
if premium { 500 } else { 100 }
}
fn status(users: Option<u32>) -> &'static str {
match users {
Some(LIMIT) => "lotado", // ✅ uma constante
Some(_) => "aberto",
None => "fechado",
}
}
fn status_for(users: Option<u32>, premium: bool) -> &'static str {
match users {
Some(n) if n >= limit_for(premium) => "lotado", // ✅ chama a função num guard
Some(_) => "aberto",
None => "fechado",
}
}
fn main() {
println!("{}", status(Some(100)));
println!("{}", status(Some(42)));
println!("{}", status(None));
println!("{}", status_for(Some(100), false));
println!("{}", status_for(Some(100), true));
}

Saída:

lotado
aberto
fechado
lotado
aberto
▶ Experimente você mesmo

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

Depois que uma variante unitária ganha um valor. Event::Logout era uma variante unitária, e você a mudou para Logout(u64). Agora todo braço Event::Logout => dá E0532. Correção: Event::Logout(_) =>, ou Event::Logout(at) => se você precisa do valor.

Quando você só quer saber o tipo do valor. Quem vem de Java ou TypeScript pode escrever if let Shape::Circle = shape para perguntar “é um círculo?”. Escreva if let Shape::Circle(_) = shape, ou matches!(shape, Shape::Circle(_)) para ter um bool rapidinho.

Sem o prefixo Shape:: o código é E0530. Se você escreve um nome sozinho, como Ok => ou Circle => depois de use Shape::*;, o rustc lê isso como uma variável nova. Ele mostra o E0530, match bindings cannot shadow tuple variants (bindings do match não podem esconder variantes de tupla), com a ajuda try specify the pattern arguments: `Ok(..)` . A correção é a mesma: acrescente os parênteses.

Teste o que aprendeu

1. Para enum Shape { Circle(f64), Empty }, qual braço de match compila?

2. O rustc diz "expected tuple struct or tuple variant, found unit variant Status::Active". Qual é a correção?

3. struct Point { x: i32, y: i32 }: como você a desestrutura com let?

Pontuação: 0 / 3