Pular para o conteúdo

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.

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 ^^^ 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”, mas Circle guarda um f64, então um padrão correto precisa de parênteses: Circle(_) ou Circle(..).
  • “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 de match
  • let bindings cannot shadow ...: num let ou if let
  • function 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.

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.

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.14
quadrado: 4.00
▶ Experimente você mesmo

O .. quer dizer “o que estiver dentro”, e continua funcionando se a variante ganhar mais valores no futuro. Veja Ignorando partes com _ e ...

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 struct

A 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 m
altura: 1.8 m
total: 5.5 m
▶ Experimente você mesmo

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

Aqui 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ão
static 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:

lotado
aberto
lotado
▶ Experimente você mesmo

Para um número simples, você quase nunca vai precisar de static. O const é a escolha de costume; veja Constantes.

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";.

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