Errore Rust E0530: match bindings cannot shadow tuple variants (nome già usato)
E0530 significa: un nome nel tuo pattern è già occupato. Hai scritto un nome semplice, come Circle, dove di solito Rust crea una nuova variabile. Ma in questo scope Circle significa già un’altra cosa: una variante tupla, una tuple struct o una static. Rust si rifiuta di nasconderla in silenzio dietro una nuova variabile, perché non sarebbe quasi mai quello che intendevi. Il caso classico è un ramo di match Circle => dopo use Shape::*;, e di solito la correzione sono due caratteri: Circle(..). (Questa pagina fa parte di Errori del compilatore Rust spiegati.)
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”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(..)`Il compilatore dice: le variabili create da un match non possono oscurare (shadowing) una variante tupla. Questo è il programma che produce l’errore:
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)));}Cosa significa
Sezione intitolata “Cosa significa”Il ^^^ indica Circle alla riga 10, e il --- alla riga 6 mostra da dove viene quel nome: use Shape::*; ha portato in scope la variante Shape::Circle.
In un pattern, un nome semplice come x o other crea una nuova variabile che corrisponde a qualsiasi cosa. Quindi Circle => potrebbe significare due cose:
- «confronta con la variante
Circle», maCirclecontiene unf64, quindi un pattern corretto ha bisogno delle tonde:Circle(_)oCircle(..). - «accetta qualsiasi cosa e chiamala
Circle», una nuova variabile che nasconderebbe la variante.
Rust non tira a indovinare. La prima riga ti dice con che tipo di nome sei andato in conflitto, e la prima parola ti dice dove:
match bindings cannot shadow ...: in un ramo dimatchlet bindings cannot shadow ...: in unleto unif letfunction parameters cannot shadow ...: nella lista dei parametri di una funzione
e finisce con tuple variants, tuple structs o statics.
È come chiamare il tuo cane «Dottore». Ogni volta che qualcuno grida «Dottore!» in sala d’attesa, nessuno sa a chi si riferisce.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Senza questa regola, Circle => sarebbe una nuova variabile chiamata Circle. Corrisponderebbe a ogni valore, e ogni ramo successivo sarebbe codice morto. Il programma compilerebbe, e poi stamperebbe «circle» anche per i quadrati. È un bug fastidioso che si nasconde dietro codice dall’aria corretta.
Per questo Rust dà errore ogni volta che una nuova variabile prenderebbe il nome di una variante tupla, di una tuple struct o di una static. O dici che cosa intendi con le tonde, o scegli un altro nome. Le varianti unit come None e le costanti (const) sono diverse: sono pattern validi da soli, quindi Rust le legge come «confronta con questo valore». Vedi Pattern matching in Rust ed Enum in Rust.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: aggiungi (..) o (_) per confrontare la variante
Sezione intitolata “Soluzione 1: aggiungi (..) o (_) per confrontare la variante”Scegli questa quando il messaggio dice tuple variants o tuple structs, il caso più comune. Intendevi la variante, quindi dalle le sue tonde, come suggerisce l’help di rustc. Scrivere il percorso completo, Shape::Circle(_), è ancora più chiaro:
enum Shape { Circle(f64), Square(f64),}
use Shape::*;
fn name(shape: &Shape) -> &'static str { match shape { Circle(..) => "cerchio", // ✅ la variante, con qualsiasi valore dentro Square(_) => "quadrato", }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ percorso completo, e usiamo il valore 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)); }}Output:
cerchio: 3.14quadrato: 4.00.. significa «qualunque cosa ci sia dentro», e continua a funzionare se in futuro la variante riceve altri valori. Vedi Pattern matching in Rust.
Soluzione 2: rinomina la variabile
Sezione intitolata “Soluzione 2: rinomina la variabile”Scegli questa quando volevi davvero una nuova variabile, e il suo nome coincide per caso con un tipo. Succede spesso con let e con i parametri di funzione, quando chiami una variabile come il suo tipo:
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 structIl programma che lo produce:
struct Meters(f64);
fn main() { let Meters = 5.0; // ❌ `Meters` is a tuple struct println!("{}", Meters);}Lo stile dei nomi di Rust risolve il problema per te: tipi e varianti sono in CamelCase, le variabili in snake_case. Usa un nome minuscolo e il conflitto sparisce:
struct Meters(f64);
fn total(meters: &[Meters]) -> f64 { meters.iter().map(|m| m.0).sum()}
fn main() { let meters = 5.0; // ✅ un nome di variabile minuscolo println!("{} m", meters);
let Meters(height) = Meters(1.8); // ✅ oppure scomponi la tuple struct println!("altezza: {} m", height);
println!("totale: {} m", total(&[Meters(2.0), Meters(3.5)]));}Output:
5 maltezza: 1.8 mtotale: 5.5 mLo stesso vale per un parametro: fn show(Point: i32) dà function parameters cannot shadow tuple structs, e fn show(point: i32) lo risolve. Vedi Variabili in Rust.
Soluzione 3: usa una const (o una match guard) al posto di una static
Sezione intitolata “Soluzione 3: usa una const (o una match guard) al posto di una static”Scegli questa quando il messaggio dice statics. Probabilmente volevi confrontare con un valore fisso. Una static non si può usare come pattern, una const sì:
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 staticIl programma che lo produce:
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));}Cambia static in const. Se deve restare una static (per esempio perché altro codice ne prende l’indirizzo), lega il valore a un nome e confronta in una match guard:
const LIMIT: u32 = 100; // ✅ una const funziona come patternstatic MAX_USERS: u32 = 500; // una static resta una static
fn status(users: u32) -> &'static str { match users { LIMIT => "pieno", _ => "aperto", }}
fn premium_status(users: u32) -> &'static str { match users { n if n >= MAX_USERS => "pieno", // ✅ confronta una static in una guard _ => "aperto", }}
fn main() { println!("{}", status(100)); println!("{}", status(42)); println!("{}", premium_status(500));}Output:
pienoapertopienoPer un semplice numero raramente ti serve una static. Di solito si sceglie const; vedi Variabili in Rust.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Ok => o Some => senza tonde. Ok, Err e Some sono varianti tupla del prelude, quindi match result { Ok => ... } dà E0530 con l’help try specify the pattern arguments: `Ok(..)` . Correzione: Ok(_) => oppure Ok(value) =>.
Dentro if let. if let Some(Some) = x cerca di chiamare Some il valore interno e dà let bindings cannot shadow tuple variants. Correzione: un nome minuscolo, if let Some(inner) = x.
Con il percorso completo è invece E0532. Shape::Circle => non può essere una nuova variabile (il nome di una variabile non contiene ::), quindi rustc segnala E0532, expected unit struct, unit variant or constant, found tuple variant. Stessa correzione: aggiungi (_) o (..).
Un let con il nome di una unit struct dà E0308. Con struct Guest;, la riga let Guest = "Ana"; non crea affatto una variabile: rustc legge Guest come la unit struct e segnala E0308 (tipi che non corrispondono), dicendo `Guest` is interpreted as a unit struct, not a new binding. Correzione: rinomina la variabile, let guest = "Ana";.
Errori correlati
Sezione intitolata “Errori correlati”- E0532: expected unit struct, unit variant or constant, found tuple variant: lo stesso sbaglio scritto con un percorso, come
Shape::Circle =>. - E0533: expected unit struct, unit variant or constant, found struct variant: una variante con campi nominati usata senza
{ .. }. - E0004: non-exhaustive patterns: dopo aver sistemato i rami, il
matchdeve comunque coprire ogni variante. - E0308: mismatched types: quello che dà un
letcon il nome di una unit struct. - E0425: cannot find value in this scope: il problema opposto, un nome che non esiste proprio.
- Tutti gli errori del compilatore spiegati
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Dopo use Shape::*;, dove Circle(f64) è una variante, quale ramo di match compila?
2. rustc dice "let bindings cannot shadow tuple structs" per let Meters = 5.0;. Qual è la correzione più semplice?
3. static LIMIT: u32 = 100; non si può usare come pattern di un match. Che cosa invece sì?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0530 — Rust error codes index (in inglese): la spiegazione ufficiale, con il caso del
(_)mancante e il casostaticcontroconst. - Pattern Syntax — The Rust Book (in inglese): confrontare variabili con nome, scomporre enum e ignorare valori con
_e... - Identifier patterns — The Rust Reference (in inglese): la regola esatta per capire quando un nome in un pattern è una nuova variabile e quando si riferisce a qualcosa che esiste già.
- Destructuring enums — Rust by Example (in inglese): varianti unit e tupla confrontate fianco a fianco.
- Static items — The Rust Reference (in inglese): in che cosa una
staticè diversa da unaconst(un unico posto fisso in memoria, non un valore copiato a ogni uso).