Ir al contenido

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.)

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)));
}

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”, pero Circle guarda un f64, así que un patrón correcto necesita paréntesis: Circle(_) o Circle(..).
  • “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 de match
  • let bindings cannot shadow ...: en un let o un if let
  • function 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.

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.

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.14
cuadrado: 4.00
▶ Pruébalo tú mismo

.. 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 m
altura: 1.8 m
total: 5.5 m
▶ Pruébalo tú mismo

Lo 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ón
static 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:

lleno
abierto
lleno
▶ Pruébalo tú mismo

Para un simple número casi nunca necesitas un static. Lo habitual es const; mira Constantes.

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

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