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.)
A mensagem de erro
Seção intitulada “A mensagem de erro”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 que significa
Seção intitulada “O que significa”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::EmptyouNone - 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.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”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.
Como corrigir
Seção intitulada “Como corrigir”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.14retângulo: 6.00nada: 0.001 círculo(s)O (..) é prático para variantes com vários valores, e continua funcionando se você acrescentar mais um depois. Veja Ignorando partes com _ e ...
Correção 2: Tire o () de uma variante unitária
Seção intitulada “Correção 2: Tire o () de uma variante unitária”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:
ativobanido (spam)ActiveSe 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 = 4esquerda = -1, cima = 72.5 mPara 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:
lotadoabertofechadolotadoabertoOs 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 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.
Erros relacionados
Seção intitulada “Erros relacionados”- E0533: expected unit struct, unit variant or constant, found struct variant: o mesmo erro para variantes com campos nomeados; acrescente
{ .. }. - E0164: expected tuple struct or tuple variant, found struct variant: parênteses numa variante com campos nomeados, ou numa constante ou função associada.
- E0023: wrong number of fields in a tuple pattern (em inglês): os parênteses estão certos, mas você deu nomes demais ou de menos.
- E0026: struct or variant does not have a field named x: um nome de campo errado dentro das chaves de um padrão.
- E0004: non-exhaustive patterns: depois de corrigir os braços, o
matchainda precisa cobrir todas as variantes. - 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(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
Para saber mais
Seção intitulada “Para saber mais”- E0532 — Rust error codes index (em inglês): a explicação oficial deste erro.
- Pattern Syntax — The Rust Book (em inglês): como desestruturar structs e enums, ignorar valores com
_e.., e usar match guards. - Destructuring enums — Rust by Example (em inglês): variantes unitárias e de tupla casadas lado a lado.
- Destructuring structs — Rust by Example (em inglês): chaves para campos nomeados, parênteses para tuple structs.
- Patterns — The Rust Reference (em inglês): as regras exatas para padrões de caminho, de tuple struct e de struct.