Erro E0530 do Rust: match bindings cannot shadow tuple variants (nome já usado)
O E0530 quer dizer: um nome no seu padrão já está ocupado. Você escreveu um nome simples, como Circle, num lugar onde o Rust normalmente criaria uma variável nova. Só que Circle já significa outra coisa nesse escopo: uma tuple variant (variante com valores entre parênteses), uma tuple struct ou um static. O Rust se recusa a escondê-lo em silêncio atrás de uma variável nova, porque isso quase nunca seria o que você queria. O caso clássico é um braço de match Circle => depois de use Shape::*;, e a correção costuma ter dois caracteres: Circle(..). Esta página faz parte do guia de erros do compilador.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0530]: match bindings cannot shadow tuple variants --> src/main.rs:10:9 | 6 | use Shape::*; | -------- the tuple variant `Circle` is imported here...10 | Circle => "circle", // ❌ `Circle` holds a value | ^^^^^^ | | | cannot be named the same as a tuple variant | help: try specify the pattern arguments: `Circle(..)`Em português: “os bindings (nomes) de um match não podem esconder tuple variants”. A seta diz que o nome não pode ser igual ao de uma tuple variant, e a ajuda sugere escrever os argumentos do padrão: Circle(..).
Este é o programa que gera o erro:
enum Shape { Circle(f64), Square(f64),}
use Shape::*;
fn name(shape: &Shape) -> &'static str { match shape { Circle => "circle", // ❌ `Circle` holds a value Square(_) => "square", }}
fn main() { println!("{}", name(&Circle(1.0)));}(O comentário quer dizer “o 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 Circle na linha 10, e o --- na linha 6 mostra de onde vem esse nome: o use Shape::*; trouxe a variante Shape::Circle para o escopo.
Num padrão, um nome simples com cara de variável, como x ou other, cria uma variável nova que aceita qualquer coisa. Então Circle => poderia querer dizer duas coisas:
- “compare com a variante
Circle”, masCircleguarda umf64, então um padrão correto precisa de parênteses:Circle(_)ouCircle(..). - “aceite qualquer coisa e chame de
Circle”, uma variável nova que esconderia a variante.
O Rust não tenta adivinhar. O título da mensagem diz com que tipo de nome você colidiu, e a primeira palavra diz onde:
match bindings cannot shadow ...: num braço dematchlet bindings cannot shadow ...: numletouif letfunction parameters cannot shadow ...: na lista de parâmetros de uma função
e ela termina em tuple variants, tuple structs ou statics.
É como dar ao seu cachorro o nome de “Doutor”. Toda vez que alguém grita “Doutor!” na sala de espera, ninguém sabe de quem estão falando.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Sem essa regra, Circle => seria uma variável nova chamada Circle. Ela aceitaria todos os valores, e todos os braços depois dela virariam código morto. O seu programa compilaria e depois imprimiria “circle” também para os quadrados. É um bug traiçoeiro, escondido atrás de um código que parece certo.
Por isso o Rust dá erro sempre que uma variável nova pegaria o nome de uma tuple variant, de uma tuple struct ou de um static. Ou você diz o que quer com parênteses, ou escolhe outro nome. Unit variants (variantes sem valores) como None e constantes (const) são diferentes: elas já são padrões válidos sozinhas, então o Rust as lê como “compare com este valor”. Veja Pattern matching e Enums.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Acrescente (..) ou (_) para casar com a variante
Seção intitulada “Correção 1: Acrescente (..) ou (_) para casar com a variante”Escolha esta quando a mensagem diz tuple variants ou tuple structs, que é o caso mais comum. Você queria a variante, então dê a ela os seus parênteses, como a ajuda do rustc sugere. Escrever o caminho completo, Shape::Circle(_), fica ainda mais claro:
enum Shape { Circle(f64), Square(f64),}
use Shape::*;
fn name(shape: &Shape) -> &'static str { match shape { Circle(..) => "círculo", // ✅ a variante, com qualquer valor dentro Square(_) => "quadrado", }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ caminho completo, usando o valor Shape::Square(side) => side * side, }}
fn main() { let shapes = [Circle(1.0), Square(2.0)]; for shape in &shapes { println!("{}: {:.2}", name(shape), area(shape)); }}Saída:
círculo: 3.14quadrado: 4.00O .. quer dizer “o que estiver dentro”, e continua funcionando se a variante ganhar mais valores no futuro. Veja Ignorando partes com _ e ...
Correção 2: Mude o nome da variável
Seção intitulada “Correção 2: Mude o nome da variável”Escolha esta quando você queria mesmo uma variável nova, e o nome dela só por acaso é igual ao de um tipo. Isso acontece muito com let e com parâmetros de funções, quando você dá à variável o nome do tipo dela:
error[E0530]: let bindings cannot shadow tuple structs --> src/main.rs:4:9 |1 | struct Meters(f64); | ------------------- the tuple struct `Meters` is defined here...4 | let Meters = 5.0; // ❌ `Meters` is a tuple struct | ^^^^^^ cannot be named the same as a tuple structA mensagem diz que o nome não pode ser igual ao de uma tuple struct, e mostra onde a tuple struct Meters foi definida. O programa por trás dela:
struct Meters(f64);
fn main() { let Meters = 5.0; // ❌ `Meters` is a tuple struct println!("{}", Meters);}(O comentário em inglês diz “Meters é uma tuple struct”.) O estilo de nomes do Rust resolve isso para você: tipos e variantes usam CamelCase, variáveis usam snake_case. Use um nome em minúsculas e o conflito some:
struct Meters(f64);
fn total(meters: &[Meters]) -> f64 { meters.iter().map(|m| m.0).sum()}
fn main() { let meters = 5.0; // ✅ um nome de variável em minúsculas println!("{} m", meters);
let Meters(height) = Meters(1.8); // ✅ ou desestruture a tuple struct println!("altura: {} m", height);
println!("total: {} m", total(&[Meters(2.0), Meters(3.5)]));}Saída:
5 maltura: 1.8 mtotal: 5.5 mO mesmo vale para um parâmetro: fn show(Point: i32) dá function parameters cannot shadow tuple structs (parâmetros de função não podem esconder tuple structs), e fn show(point: i32) resolve. Veja Regras de nomes.
Correção 3: Use um const (ou um match guard) no lugar de um static
Seção intitulada “Correção 3: Use um const (ou um match guard) no lugar de um static”Escolha esta quando a mensagem diz statics. Você provavelmente queria comparar com um valor fixo. Um static não pode ser usado como padrão, mas um const pode:
error[E0530]: match bindings cannot shadow statics --> src/main.rs:5:9 |1 | static LIMIT: u32 = 100; | ------------------------ the static `LIMIT` is defined here...5 | LIMIT => "full", // ❌ a static can't be a pattern | ^^^^^ cannot be named the same as a staticAqui o nome colide com o static LIMIT. O programa por trás dela:
static LIMIT: u32 = 100;
fn status(users: u32) -> &'static str { match users { LIMIT => "full", // ❌ a static can't be a pattern _ => "open", }}
fn main() { println!("{}", status(100));}(O comentário em inglês diz “um static não pode ser um padrão”.) Troque static por const. Se ele precisar continuar sendo um static (por exemplo, porque outro código usa o endereço dele), dê um nome ao valor e compare num match guard (condição if no braço):
const LIMIT: u32 = 100; // ✅ um const funciona como padrãostatic MAX_USERS: u32 = 500; // um static continua sendo static
fn status(users: u32) -> &'static str { match users { LIMIT => "lotado", _ => "aberto", }}
fn premium_status(users: u32) -> &'static str { match users { n if n >= MAX_USERS => "lotado", // ✅ compare um static num guard _ => "aberto", }}
fn main() { println!("{}", status(100)); println!("{}", status(42)); println!("{}", premium_status(500));}Saída:
lotadoabertolotadoPara um número simples, você quase nunca vai precisar de static. O const é a escolha de costume; veja Constantes.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Ok => ou Some => sem parênteses. Ok, Err e Some são tuple variants do prelude, então match result { Ok => ... } dá E0530 com a ajuda try specify the pattern arguments: `Ok(..)` . Correção: Ok(_) => ou Ok(value) =>.
Dentro de um if let. if let Some(Some) = x tenta chamar o valor de dentro de Some e dá let bindings cannot shadow tuple variants. Correção: um nome em minúsculas, if let Some(inner) = x.
Com o caminho completo, o erro é o E0532. Shape::Circle => não pode ser uma variável nova (um nome de variável não tem ::), então o rustc mostra o E0532, expected unit struct, unit variant or constant, found tuple variant. A correção é a mesma: acrescente (_) ou (..).
Um let com o nome de uma unit struct dá E0308. Com struct Guest;, a linha let Guest = "Ana"; nem cria uma variável: o rustc lê Guest como a unit struct e mostra o E0308 (tipos incompatíveis), dizendo `Guest` is interpreted as a unit struct, not a new binding (Guest é lido como unit struct, não como um nome novo). Correção: mude o nome da variável, let guest = "Ana";.
Erros relacionados
Seção intitulada “Erros relacionados”- E0532: expected unit struct, unit variant or constant, found tuple variant: o mesmo engano escrito com um caminho, como
Shape::Circle =>. - E0533: expected unit struct, unit variant or constant, found struct variant: uma variante com campos nomeados usada sem
{ .. }. - E0004: non-exhaustive patterns: depois de corrigir os braços, o
matchainda precisa cobrir todas as variantes. - E0308: mismatched types: o que um
letcom o nome de uma unit struct dá. - E0425: cannot find value in this scope: o problema contrário, um nome que nem existe.
- Todos os erros do compilador
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Depois de use Shape::*;, onde Circle(f64) é uma variante, qual braço de match compila?
2. O rustc diz "let bindings cannot shadow tuple structs" para let Meters = 5.0;. Qual é a correção mais simples?
3. static LIMIT: u32 = 100; não pode ser usado como padrão num match. O que pode?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0530 — Rust error codes index (em inglês): a explicação oficial, com o caso do
(_)que falta e o casostaticcontraconst. - Pattern Syntax — The Rust Book (em inglês): casar com variáveis nomeadas, desestruturar enums e ignorar valores com
_e... - Identifier patterns — The Rust Reference (em inglês): a regra exata de quando um nome num padrão é uma variável nova e quando ele se refere a algo que já existe.
- Destructuring enums — Rust by Example (em inglês): unit variants e tuple variants lado a lado num match.
- Static items — The Rust Reference (em inglês): como um
staticdifere de umconst(um lugar fixo na memória, não um valor copiado em cada uso).