Aller au contenu

Erreur Rust E0530 : match bindings cannot shadow tuple variants (nom déjà pris)

E0530 veut dire : un nom de votre motif (pattern) est déjà pris. Vous avez écrit un nom tout seul, comme Circle, là où Rust crée normalement une nouvelle variable. Mais dans cette portée, Circle désigne déjà autre chose : une variante tuple, une struct tuple ou un static. Rust refuse de le cacher en silence derrière une nouvelle variable, parce que ce ne serait presque jamais ce que vous vouliez. Le cas classique, c’est une branche de match Circle => après use Shape::*;, et la correction tient le plus souvent en deux caractères : Circle(..). Cette page fait partie du guide des erreurs du compilateur Rust.

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` contient une valeur
| ^^^^^^
| |
| cannot be named the same as a tuple variant
| help: try specify the pattern arguments: `Circle(..)`

Le compilateur vous dit : « les liaisons d’un match ne peuvent pas masquer des variantes tuples ». Le nom ne peut pas être le même que celui d’une variante tuple, et l’aide propose d’indiquer les arguments du motif : Circle(..).

Voici le programme qui la provoque :

enum Shape {
Circle(f64),
Square(f64),
}
use Shape::*;
fn name(shape: &Shape) -> &'static str {
match shape {
Circle => "circle", // ❌ `Circle` contient une valeur
Square(_) => "square",
}
}
fn main() {
println!("{}", name(&Circle(1.0)));
}

Les ^^^ pointent Circle à la ligne 10, et les --- de la ligne 6 montrent d’où vient ce nom : use Shape::*; a importé la variante Shape::Circle dans la portée.

Dans un motif, un simple nom comme x ou other crée une nouvelle variable qui accepte n’importe quelle valeur. Circle => pourrait donc vouloir dire deux choses :

  • « teste la variante Circle » ; mais Circle contient un f64, donc un motif correct a besoin de parenthèses : Circle(_) ou Circle(..).
  • « accepte n’importe quoi et appelle-le Circle » : une nouvelle variable, qui cacherait la variante.

Rust ne devine pas. Le titre de l’erreur vous dit avec quelle sorte de nom il y a conflit, et le premier mot vous dit où :

  • match bindings cannot shadow ... : dans une branche de match
  • let bindings cannot shadow ... : dans un let ou un if let
  • function parameters cannot shadow ... : dans la liste des paramètres d’une fonction

et il se termine par tuple variants (variantes tuples), tuple structs (structs tuples) ou statics.

C’est comme appeler son chien « Docteur ». Chaque fois que quelqu’un crie « Docteur ! » dans la salle d’attente, personne ne sait de qui on parle.

Sans cette règle, Circle => serait une nouvelle variable nommée Circle. Elle accepterait toutes les valeurs, et chaque branche suivante deviendrait du code mort. Votre programme compilerait, puis afficherait « circle » aussi pour les carrés. C’est un bug sournois, caché derrière du code qui a l’air juste.

Rust en fait donc une erreur chaque fois qu’une nouvelle variable prendrait le nom d’une variante tuple, d’une struct tuple ou d’un static. Soit vous dites ce que vous voulez avec des parenthèses, soit vous choisissez un autre nom. Les variantes unité comme None et les constantes (const) sont différentes : ce sont des motifs valides à elles seules, donc Rust les lit comme « teste cette valeur ». Voir Le pattern matching et Les enums.

Solution 1 : ajouter (..) ou (_) pour tester la variante

Section intitulée « Solution 1 : ajouter (..) ou (_) pour tester la variante »

Choisissez-la quand le message dit tuple variants ou tuple structs : c’est le cas le plus courant. Vous vouliez la variante, alors donnez-lui ses parenthèses, comme le propose l’aide de rustc. Écrire le chemin complet, Shape::Circle(_), est encore plus clair :

enum Shape {
Circle(f64),
Square(f64),
}
use Shape::*;
fn name(shape: &Shape) -> &'static str {
match shape {
Circle(..) => "cercle", // ✅ la variante, quelle que soit sa valeur
Square(_) => "carré",
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ chemin complet, et on utilise la valeur
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));
}
}

Sortie :

cercle : 3.14
carré : 4.00
▶ Essayez par vous-même

.. veut dire « peu importe ce qu’il y a dedans », et continue de marcher si la variante reçoit plus tard d’autres valeurs. Voir Ignorer des parties avec _ et ...

Choisissez-la quand vous vouliez vraiment une nouvelle variable, et que son nom tombe par hasard sur celui d’un type. Ça arrive souvent avec let et les paramètres de fonction, quand on nomme une variable d’après son type :

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` est une struct tuple
| ^^^^^^ cannot be named the same as a tuple struct

Ici, rustc dit « les liaisons d’un let ne peuvent pas masquer des structs tuples » : la variable ne peut pas porter le même nom que la struct tuple Meters.

Le programme qui la provoque :

struct Meters(f64);
fn main() {
let Meters = 5.0; // ❌ `Meters` est une struct tuple
println!("{}", Meters);
}

Les conventions de nommage de Rust règlent ça pour vous : les types et les variantes s’écrivent en CamelCase, les variables en snake_case. Prenez un nom en minuscules et le conflit disparaît :

struct Meters(f64);
fn total(meters: &[Meters]) -> f64 {
meters.iter().map(|m| m.0).sum()
}
fn main() {
let meters = 5.0; // ✅ un nom de variable en minuscules
println!("{} m", meters);
let Meters(height) = Meters(1.8); // ✅ ou bien on déstructure la struct tuple
println!("hauteur : {} m", height);
println!("total : {} m", total(&[Meters(2.0), Meters(3.5)]));
}

Sortie :

5 m
hauteur : 1.8 m
total : 5.5 m
▶ Essayez par vous-même

C’est pareil pour un paramètre : fn show(Point: i32) donne function parameters cannot shadow tuple structs, et fn show(point: i32) corrige l’erreur. Voir Règles de nommage.

Solution 3 : utiliser une const (ou une garde de match) au lieu d’un static

Section intitulée « Solution 3 : utiliser une const (ou une garde de match) au lieu d’un static »

Choisissez-la quand le message dit statics. Vous vouliez sans doute comparer avec une valeur fixe. Un static ne peut pas servir de motif, mais une const, si :

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", // ❌ un static ne peut pas être un motif
| ^^^^^ cannot be named the same as a static

Cette fois, rustc dit « les liaisons d’un match ne peuvent pas masquer des statics » : le nom ne peut pas être le même que celui du static LIMIT.

Le programme qui la provoque :

static LIMIT: u32 = 100;
fn status(users: u32) -> &'static str {
match users {
LIMIT => "full", // ❌ un static ne peut pas être un motif
_ => "open",
}
}
fn main() {
println!("{}", status(100));
}

Remplacez static par const. Si la valeur doit rester un static (par exemple parce que d’autres parties du code prennent son adresse), liez la valeur à un nom et comparez-la dans une garde de match (match guard) :

const LIMIT: u32 = 100; // ✅ une const peut servir de motif
static MAX_USERS: u32 = 500; // un static reste un static
fn status(users: u32) -> &'static str {
match users {
LIMIT => "plein",
_ => "ouvert",
}
}
fn premium_status(users: u32) -> &'static str {
match users {
n if n >= MAX_USERS => "plein", // ✅ on compare un static dans une garde
_ => "ouvert",
}
}
fn main() {
println!("{}", status(100));
println!("{}", status(42));
println!("{}", premium_status(500));
}

Sortie :

plein
ouvert
plein
▶ Essayez par vous-même

Pour un simple nombre, vous aurez rarement besoin d’un static. const est le choix habituel ; voir Les constantes.

Ok => ou Some => sans parenthèses. Ok, Err et Some sont des variantes tuples du prélude, donc match result { Ok => ... } donne E0530 avec l’aide try specify the pattern arguments: `Ok(..)` . Correction : Ok(_) => ou Ok(value) =>.

Dans un if let. if let Some(Some) = x essaie d’appeler la valeur intérieure Some et donne let bindings cannot shadow tuple variants. Correction : un nom en minuscules, if let Some(inner) = x.

Avec le chemin complet, c’est E0532. Shape::Circle => ne peut pas être une nouvelle variable (un nom de variable n’a pas de ::), donc rustc signale E0532, expected unit struct, unit variant or constant, found tuple variant. Même correction : ajoutez (_) ou (..).

Un let avec le nom d’une struct unité, c’est E0308. Avec struct Guest;, la ligne let Guest = "Ana"; ne crée pas de variable du tout : rustc lit Guest comme la struct unité et signale E0308 (types incompatibles), en précisant `Guest` is interpreted as a unit struct, not a new binding (« Guest est interprété comme une struct unité, pas comme une nouvelle liaison »). Correction : renommez la variable, let guest = "Ana";.

Petit quiz

1. Après use Shape::*;, où Circle(f64) est une variante, quelle branche de match compile ?

2. rustc dit « let bindings cannot shadow tuple structs » pour let Meters = 5.0;. Quelle est la correction la plus simple ?

3. static LIMIT: u32 = 100; ne peut pas servir de motif dans un match. Qu'est-ce qui le peut ?

Score : 0 / 3