Aller au contenu

Erreur Rust E0532 : expected unit struct, unit variant or constant, found tuple variant

E0532 veut dire : la forme de votre motif (pattern) ne correspond pas à la forme de ce que vous avez nommé. Le cas classique, c’est une branche de match comme Shape::Circle => pour une variante qui contient des données, Circle(f64). Rust veut les parenthèses : Shape::Circle(_). L’erreur inverse a le même code, avec l’autre formulation « expected tuple struct or tuple variant » : des parenthèses après quelque chose qui n’a pas de données entre parenthèses, comme Status::Active(). Dans les deux cas, la correction tient en une ligne. Cette page fait partie du guide des erreurs du compilateur Rust.

error[E0532]: expected unit struct, unit variant or constant, found tuple variant `Shape::Circle`
--> src/main.rs:8:9
|
2 | Circle(f64),
| ----------- `Shape::Circle` defined here
...
8 | Shape::Circle => "circle", // ❌ `Circle` contient une valeur
| ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Shape::Circle(_)`

Le compilateur vous dit : « on attendait une struct unité, une variante unité ou une constante, mais on a trouvé la variante tuple Shape::Circle ».

Voici le programme qui la provoque :

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

Les ^^^ pointent Shape::Circle à la ligne 8, et les --- de la ligne 2 montrent comment elle a été définie : Circle(f64), une variante tuple qui porte un f64. Un motif qui n’est qu’un nom, sans rien derrière, doit être l’une de ces trois choses :

  • une struct unité (unit struct), comme struct Empty;
  • une variante unité (unit variant), une variante sans données, comme Shape::Empty ou None
  • une constante, comme const LIMIT: u32 = 100;

Shape::Circle n’est rien de tout ça. La ligne help: donne tout de suite la correction : utilisez plutôt la syntaxe de motif des variantes tuples, Shape::Circle(_), c’est-à-dire « un cercle, quelle que soit sa valeur ».

L’autre titre de E0532 est son reflet dans le miroir : expected tuple struct or tuple variant, found unit variant `Status::Active` (ou found struct, ou found constant). Là, c’est vous qui avez mis des parenthèses après un nom, et ce que vous avez nommé ne prend pas de valeurs entre parenthèses.

C’est comme un formulaire qui demande « Animal : chien (nom : ____) ». Écrire seulement « chien » laisse la case du nom vide, et écrire « poisson (nom : Bulle) » là où le formulaire dit « poisson » sans case ajoute une case qui n’existe pas.

Chaque struct et chaque variante d’enum a l’une de ces trois formes, et vous l’écrivez de la même façon quand vous la créez et quand vous la testez dans un match (voir Les enums peuvent contenir des données) :

Sorte La créer La tester dans un motif
Unité : Empty Shape::Empty Shape::Empty
Tuple : Circle(f64) Shape::Circle(1.0) Shape::Circle(r) ou Shape::Circle(..)
Struct : Rect { w: f64, h: f64 } Shape::Rect { w: 2.0, h: 3.0 } Shape::Rect { w, h } ou Shape::Rect { .. }

Comme les formes sont strictes, un motif ressemble toujours à la valeur qu’il teste, et en lisant un match vous voyez quelles données chaque branche reçoit. Ça aide aussi quand vous modifiez un type : si Empty reçoit plus tard une valeur et devient Empty(u32), chaque ancienne branche Shape::Empty est signalée, au lieu de se mettre en silence à reconnaître autre chose.

Solution 1 : ajouter (_), (..) ou des noms pour les valeurs

Section intitulée « Solution 1 : ajouter (_), (..) ou des noms pour les valeurs »

Choisissez-la quand le message dit found tuple variant ou found tuple struct : c’est le E0532 le plus courant. Utilisez _ pour chaque valeur dont vous n’avez pas besoin, .. pour les ignorer toutes d’un coup, ou un nom quand vous voulez utiliser la valeur :

enum Shape {
Circle(f64),
Rect(f64, f64),
Empty,
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle(_) => "cercle", // ✅ un champ, ignoré
Shape::Rect(..) => "rectangle", // ✅ n'importe quel nombre de champs, tous ignorés
Shape::Empty => "rien", // une variante unité : pas de parenthèses
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ on lie le champ, car on en a besoin
Shape::Rect(w, h) => w * h,
Shape::Empty => 0.0,
}
}
fn main() {
let shapes = [Shape::Circle(1.0), Shape::Rect(2.0, 3.0), Shape::Empty];
for shape in &shapes {
println!("{} : {:.2}", name(shape), area(shape));
}
let circles = shapes.iter().filter(|s| matches!(s, Shape::Circle(_))).count();
println!("{} cercle(s)", circles);
}

Sortie :

cercle : 3.14
rectangle : 6.00
rien : 0.00
1 cercle(s)
▶ Essayez par vous-même

(..) est pratique pour les variantes à plusieurs valeurs, et continue de marcher si vous en ajoutez une plus tard. Voir Ignorer des parties avec _ et ...

Solution 2 : retirer les () d’une variante unité

Section intitulée « Solution 2 : retirer les () d’une variante unité »

Choisissez-la quand le message dit found unit variant ou found unit struct. La variante ne contient pas de données, il n’y a donc rien à mettre entre parenthèses :

error[E0532]: expected tuple struct or tuple variant, found unit variant `Status::Active`
--> src/main.rs:8:9
|
2 | Active,
| ------ `Status::Active` defined here
...
8 | Status::Active() => "active", // ❌ `Active` ne contient pas de données
| ^^^^^^^^^^^^^^^^ help: use this syntax instead: `Status::Active`

Ici, rustc dit « on attendait une struct tuple ou une variante tuple, mais on a trouvé la variante unité Status::Active », et l’aide propose d’écrire simplement Status::Active.

Le programme qui la provoque :

enum Status {
Active,
Banned(String),
}
fn label(s: &Status) -> &'static str {
match s {
Status::Active() => "active", // ❌ `Active` ne contient pas de données
Status::Banned(_) => "banned",
}
}
fn main() {
println!("{}", label(&Status::Active));
}

Écrivez le nom tout seul, dans le motif comme à l’endroit où vous créez la valeur :

#[derive(Debug)]
enum Status {
Active,
Banned(String),
}
fn label(s: &Status) -> String {
match s {
Status::Active => String::from("actif"), // ✅ variante unité : pas de ()
Status::Banned(reason) => format!("banni ({})", reason),
}
}
fn main() {
println!("{}", label(&Status::Active));
println!("{}", label(&Status::Banned(String::from("spam"))));
let s = Status::Active; // ✅ et pas de () non plus quand vous la créez
println!("{:?}", s);
}

Sortie :

actif
banni (spam)
Active
▶ Essayez par vous-même

Si vous vouliez que la variante porte des données, modifiez plutôt la définition, par exemple Active(u64) pour un horodatage « depuis quand », et Status::Active(_) devient alors le bon motif.

Solution 3 : utiliser des accolades pour une struct à champs nommés

Section intitulée « Solution 3 : utiliser des accolades pour une struct à champs nommés »

Choisissez-la quand le message dit found struct. Une struct à champs nommés, struct Point { x: i32, y: i32 }, se déstructure avec des accolades et les noms des champs, pas avec des parenthèses :

error[E0532]: expected tuple struct or tuple variant, found struct `Point`
--> src/main.rs:8:9
|
1 | / struct Point {
2 | | x: i32,
3 | | y: i32,
4 | | }
| |_- `Point` defined here
...
8 | let Point(x, y) = p; // ❌ `Point` a des champs nommés
| ^^^^^^^^^^^ help: use struct pattern syntax instead: `Point { x, y }`

L’aide vous propose la syntaxe de motif des structs, Point { x, y }.

Le programme qui la provoque :

struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 3, y: 4 };
let Point(x, y) = p; // ❌ `Point` a des champs nommés
println!("{} {}", x, y);
}

La suggestion de rustc, Point { x, y }, est exactement la bonne. Écrivez champ: nom quand vous voulez un autre nom de variable :

struct Point {
x: i32,
y: i32,
}
struct Meters(f64); // une struct tuple : ici, les parenthèses sont correctes
fn main() {
let p = Point { x: 3, y: 4 };
let Point { x, y } = p; // ✅ des accolades et les noms des champs
println!("x = {}, y = {}", x, y);
let q = Point { x: -1, y: 7 };
let Point { x: left, y: up } = q; // ✅ on renomme en déstructurant
println!("left = {}, up = {}", left, up);
let Meters(m) = Meters(2.5); // ✅ struct tuple, motif tuple
println!("{} m", m);
}

Sortie :

x = 3, y = 4
left = -1, up = 7
2.5 m
▶ Essayez par vous-même

Pour une variante d’enum à champs nommés, Shape::Rect(w, h) pour Rect { w: f64, h: f64 }, la même erreur donne un autre code, E0164. La correction est la même : des accolades.

Solution 4 : utiliser une constante ou une garde de match au lieu d’un appel de fonction

Section intitulée « Solution 4 : utiliser une constante ou une garde de match au lieu d’un appel de fonction »

Choisissez-la quand le message dit expected a pattern, found a function call. Un motif doit être connu à la compilation, et un appel de fonction ne l’est pas :

error[E0532]: expected a pattern, found a function call
--> src/main.rs:7:14
|
7 | Some(limit()) => "full", // ❌ un appel de fonction ne peut pas être un motif
| ^^^^^ not a tuple struct or tuple variant
|
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>

rustc dit « on attendait un motif, mais on a trouvé un appel de fonction », et la note rappelle que les appels de fonction ne sont pas permis dans les motifs.

Le programme qui la provoque :

fn limit() -> u32 {
100
}
fn status(users: Option<u32>) -> &'static str {
match users {
Some(limit()) => "full", // ❌ un appel de fonction ne peut pas être un motif
Some(_) => "open",
None => "closed",
}
}
fn main() {
println!("{}", status(Some(100)));
}

Si la valeur ne change jamais, faites-en une const : les constantes peuvent s’utiliser dans les motifs. Si elle doit être calculée, liez la valeur à un nom et comparez-la dans une garde de match (match guard) :

const LIMIT: u32 = 100; // une constante peut s'utiliser dans un motif
fn limit_for(premium: bool) -> u32 {
if premium { 500 } else { 100 }
}
fn status(users: Option<u32>) -> &'static str {
match users {
Some(LIMIT) => "plein", // ✅ une constante
Some(_) => "ouvert",
None => "fermé",
}
}
fn status_for(users: Option<u32>, premium: bool) -> &'static str {
match users {
Some(n) if n >= limit_for(premium) => "plein", // ✅ on appelle la fonction dans une garde
Some(_) => "ouvert",
None => "fermé",
}
}
fn main() {
println!("{}", status(Some(100)));
println!("{}", status(Some(42)));
println!("{}", status(None));
println!("{}", status_for(Some(100), false));
println!("{}", status_for(Some(100), true));
}

Sortie :

plein
ouvert
fermé
plein
ouvert
▶ Essayez par vous-même

Les gardes de match sont expliquées dans Les gardes : ajouter un if.

Après qu’une variante unité a reçu une valeur. Event::Logout était une variante unité, et vous l’avez changée en Logout(u64). Chaque branche Event::Logout => donne maintenant E0532. Correction : Event::Logout(_) =>, ou Event::Logout(at) => si vous avez besoin de la valeur.

Tester seulement la sorte d’une valeur. Si vous venez de Java ou de TypeScript, vous écrirez peut-être if let Shape::Circle = shape pour demander « est-ce un cercle ? ». Écrivez if let Shape::Circle(_) = shape, ou matches!(shape, Shape::Circle(_)) pour obtenir vite un bool.

Sans le préfixe Shape::, c’est E0530. Si vous écrivez un nom seul, comme Ok => ou Circle => après use Shape::*;, rustc le lit comme une nouvelle variable. Il signale E0530, match bindings cannot shadow tuple variants (les liaisons d’un match ne peuvent pas masquer des variantes tuples), avec l’aide try specify the pattern arguments: `Ok(..)` . Même correction : ajoutez les parenthèses.

Petit quiz

1. Pour enum Shape { Circle(f64), Empty }, quelle branche de match compile ?

2. rustc dit « expected tuple struct or tuple variant, found unit variant Status::Active ». Quelle est la correction ?

3. struct Point { x: i32, y: i32 } : comment la déstructurer avec let ?

Score : 0 / 3