Error E0530 de Rust: match bindings cannot shadow tuple variants
E0530 significa: un nombre de tu patrón ya está ocupado. Escribiste un nombre suelto, como Circle, en un lugar donde Rust normalmente crea una variable nueva. Pero Circle ya significa otra cosa en ese ámbito: una variante de tupla, un tuple struct o un static. Rust se niega a esconderlo en silencio detrás de una variable nueva, porque casi nunca es lo que querías. El caso clásico es una rama de match como Circle => después de use Shape::*;, y la solución suele ser de dos caracteres: Circle(..). (Esta página forma parte de Errores del compilador de Rust explicados.)
El mensaje de error
Sección titulada «El mensaje de error»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(..)`En español: “los enlaces (bindings) de un match no pueden ocultar variantes de tupla”. La etiqueta dice que el nombre no puede ser igual al de una variante de tupla, y el help te propone el patrón correcto: Circle(..).
Este es el programa que lo produce:
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)));}Qué significa
Sección titulada «Qué significa»El ^^^ señala Circle en la línea 10, y el --- de la línea 6 muestra de dónde viene ese nombre: use Shape::*; trajo la variante Shape::Circle al ámbito.
En un patrón, un nombre suelto como x u other crea una variable nueva que encaja con cualquier valor. Así que Circle => podría significar dos cosas:
- “haz match con la variante
Circle”, peroCircleguarda unf64, así que un patrón correcto necesita paréntesis:Circle(_)oCircle(..). - “haz match con cualquier cosa y llámala
Circle”, una variable nueva que ocultaría la variante.
Rust no adivina. El titular te dice con qué tipo de nombre chocaste, y la primera palabra te dice dónde:
match bindings cannot shadow ...: en una rama dematchlet bindings cannot shadow ...: en unleto unif letfunction parameters cannot shadow ...: en la lista de parámetros de una función
y termina en tuple variants (variantes de tupla), tuple structs o statics.
Es como llamar “Doctor” a tu perro. Cada vez que alguien grita “¡Doctor!” en la sala de espera, nadie sabe a quién se refiere.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»Sin esta regla, Circle => sería una variable nueva llamada Circle. Encajaría con todos los valores, y todas las ramas que vinieran después serían código muerto. Tu programa compilaría y luego diría “circle” también para los cuadrados. Es un bug muy feo, escondido detrás de un código que parece correcto.
Por eso Rust da un error siempre que una variable nueva tomaría el nombre de una variante de tupla, de un tuple struct o de un static. O dices lo que quieres con paréntesis, o eliges otro nombre. Las variantes unitarias como None y las constantes (const) son distintas: son patrones válidos por sí solas, así que Rust las lee como “haz match con este valor”. Mira Coincidencia de patrones y Enums.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»Solución 1: Añade (..) o (_) para hacer match con la variante
Sección titulada «Solución 1: Añade (..) o (_) para hacer match con la variante»Elige esta cuando el mensaje dice tuple variants o tuple structs, que es el caso más común. Querías la variante, así que ponle sus paréntesis, como sugiere el help de rustc. Escribir la ruta completa, Shape::Circle(_), es todavía más claro:
enum Shape { Circle(f64), Square(f64),}
use Shape::*;
fn name(shape: &Shape) -> &'static str { match shape { Circle(..) => "círculo", // ✅ la variante, con cualquier valor dentro Square(_) => "cuadrado", }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ ruta completa, y usamos el 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)); }}Salida:
círculo: 3.14cuadrado: 4.00.. significa “lo que haya dentro”, y sigue funcionando si más adelante la variante recibe más valores. Mira Ignorar partes con _ y ...
Solución 2: Cambia el nombre de la variable
Sección titulada «Solución 2: Cambia el nombre de la variable»Elige esta cuando de verdad querías una variable nueva y su nombre simplemente coincide con el de un tipo. Pasa a menudo con let y con los parámetros de funciones, cuando le pones a una variable el nombre de su 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 struct“Los enlaces de un let no pueden ocultar tuple structs”. El programa que lo produce:
struct Meters(f64);
fn main() { let Meters = 5.0; // ❌ `Meters` is a tuple struct println!("{}", Meters);}El estilo de nombres de Rust te lo resuelve: los tipos y las variantes van en CamelCase, las variables en snake_case. Usa un nombre en minúsculas y el choque desaparece:
struct Meters(f64);
fn total(meters: &[Meters]) -> f64 { meters.iter().map(|m| m.0).sum()}
fn main() { let meters = 5.0; // ✅ un nombre de variable en minúsculas println!("{} m", meters);
let Meters(height) = Meters(1.8); // ✅ o desestructura el tuple struct println!("altura: {} m", height);
println!("total: {} m", total(&[Meters(2.0), Meters(3.5)]));}Salida:
5 maltura: 1.8 mtotal: 5.5 mLo mismo vale para un parámetro: fn show(Point: i32) da function parameters cannot shadow tuple structs, y fn show(point: i32) lo arregla. Mira Reglas para los nombres.
Solución 3: Usa un const (o una guarda) en lugar de un static
Sección titulada «Solución 3: Usa un const (o una guarda) en lugar de un static»Elige esta cuando el mensaje dice statics. Seguramente querías comparar con un valor fijo. Un static no puede usarse como patrón, pero un 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 static“Los enlaces de un match no pueden ocultar statics”. El programa que 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 por const. Si tiene que seguir siendo un static (por ejemplo, porque otro código usa su dirección de memoria), dale un nombre al valor y compáralo en una guarda (match guard):
const LIMIT: u32 = 100; // ✅ un const funciona como patrónstatic MAX_USERS: u32 = 500; // un static sigue siendo un static
fn status(users: u32) -> &'static str { match users { LIMIT => "lleno", _ => "abierto", }}
fn premium_status(users: u32) -> &'static str { match users { n if n >= MAX_USERS => "lleno", // ✅ compara un static en una guarda _ => "abierto", }}
fn main() { println!("{}", status(100)); println!("{}", status(42)); println!("{}", premium_status(500));}Salida:
llenoabiertollenoPara un simple número casi nunca necesitas un static. Lo habitual es const; mira Constantes.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»Ok => o Some => sin paréntesis. Ok, Err y Some son variantes de tupla del prelude, así que match result { Ok => ... } da E0530 con el help try specify the pattern arguments: `Ok(..)` . Solución: Ok(_) => u Ok(value) =>.
Dentro de un if let. if let Some(Some) = x intenta llamar Some al valor de dentro y da let bindings cannot shadow tuple variants. Solución: un nombre en minúsculas, if let Some(inner) = x.
Con la ruta completa, es E0532. Shape::Circle => no puede ser una variable nueva (el nombre de una variable no lleva ::), así que rustc muestra E0532, expected unit struct, unit variant or constant, found tuple variant. La misma solución: añade (_) o (..).
Un let con el nombre de un struct unitario da E0308. Con struct Guest;, la línea let Guest = "Ana"; no crea ninguna variable: rustc lee Guest como el struct unitario y muestra E0308 (tipos que no coinciden), diciendo `Guest` is interpreted as a unit struct, not a new binding (Guest se interpreta como un struct unitario, no como un enlace nuevo). Solución: cambia el nombre de la variable, let guest = "Ana";.
Errores relacionados
Sección titulada «Errores relacionados»- E0532: expected unit struct, unit variant or constant, found tuple variant: el mismo error escrito con una ruta, como
Shape::Circle =>. - E0533: expected unit struct, unit variant or constant, found struct variant: una variante con campos con nombre usada sin
{ .. }. - E0004: non-exhaustive patterns: después de arreglar las ramas, el
matchtodavía tiene que cubrir todas las variantes. - E0308: mismatched types: lo que da un
letcon el nombre de un struct unitario. - E0425: cannot find value in this scope: el problema contrario, un nombre que no existe en absoluto.
- Todos los errores del compilador explicados
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»Comprueba lo aprendido
1. Después de use Shape::*;, donde Circle(f64) es una variante, ¿qué rama de match compila?
2. rustc dice "let bindings cannot shadow tuple structs" para let Meters = 5.0;. ¿Cuál es la solución más sencilla?
3. static LIMIT: u32 = 100; no se puede usar como patrón de un match. ¿Qué sí se puede?
Puntuación: 0 / 3
Para leer más
Sección titulada «Para leer más»- E0530 — Rust error codes index (en inglés): la explicación oficial, con el caso del
(_)que falta y el destaticfrente aconst. - Pattern Syntax — El libro de Rust (en inglés): variables con nombre en los patrones, desestructurar enums e ignorar valores con
_y... También existe una traducción al español de la comunidad del libro. - Identifier patterns — The Rust Reference (en inglés): la regla exacta de cuándo un nombre en un patrón es una variable nueva y cuándo se refiere a algo que ya existe.
- Destructuring enums — Rust by Example (en inglés): variantes unitarias y de tupla en un mismo
match. - Static items — The Rust Reference (en inglés): en qué se diferencia un
staticde unconst(un único lugar fijo en memoria, no un valor que se copia en cada uso).