Aller au contenu

Erreur Rust E0559 : variant has no field named X (champ de variante inconnu)

E0559 veut dire : vous créez une valeur d’enum avec Enum::Variant { field: value }, et l’un des champs que vous avez écrits n’existe pas dans cette variante. C’est la version enum de E0560, qui est la même erreur pour les structs. En général, c’est un nom de champ trop court ou mal écrit, un champ qui appartient à une autre variante, ou des accolades sur une variante qui attend des parenthèses. La correction tient presque toujours en un mot. (Cette page fait partie de Les erreurs du compilateur Rust expliquées.)

error[E0559]: variant `Shape::Circle` has no field named `r`
--> src/main.rs:8:33
|
8 | let shape = Shape::Circle { r: 2.0 }; // ❌ le champ s'appelle `radius`
| ^ `Shape::Circle` does not have this field
|
= note: available fields are: `radius`

Le compilateur vous dit : « la variante Shape::Circle n’a pas de champ nommé r ». L’étiquette « does not have this field » veut dire « n’a pas ce champ », et la note « available fields are » donne la liste des champs disponibles.

Voici le programme qui la provoque :

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn main() {
let shape = Shape::Circle { r: 2.0 }; // ❌ le champ s'appelle `radius`
println!("{:?}", shape);
}

Le titre nomme la variante (Shape::Circle) et le champ que vous avez écrit (r). Le ^ pointe ce champ entre les accolades. Rust a regardé la définition Circle { radius: f64 } et n’a trouvé aucun champ appelé r.

Chaque variante d’un enum a sa propre liste de champs. Shape::Circle a radius, Shape::Rectangle a width et height. Elles ne partagent pas leurs champs, même à l’intérieur du même enum.

Sous la flèche, rustc vous donne l’un de ces indices. Lisez-le en premier, il contient souvent la réponse :

  • note: available fields are: `radius` (champs disponibles : radius) : aucun nom proche. Ce sont les champs de cette variante que vous n’avez pas encore remplis.
  • help: a field with a similar name exists (un champ au nom proche existe) : une faute de frappe, comme kye pour key. rustc montre la ligne corrigée.
  • help: `Message::Write` is a tuple variant, use the appropriate syntax (Message::Write est une variante tuple, utilisez la syntaxe adaptée) : les champs de la variante n’ont pas de nom, il faut donc ( ) et pas { }.
  • note: all struct fields are already assigned (tous les champs sont déjà remplis) : vous avez rempli tous les vrais champs, et celui-ci est en trop.

C’est comme commander une pizza en demandant une « pâte large » alors que le menu ne propose qu’une « taille de pâte ». En cuisine, on comprend très bien ce que vous voulez dire, mais le bon de commande n’a aucune case qui porte ce nom.

Une variante d’enum avec des champs nommés, comme Circle { radius: f64 }, fonctionne comme une petite struct à l’intérieur de l’enum. Quand vous en créez une, Rust vérifie que vous avez donné exactement ses champs : aucun qui manque, aucun en trop, aucun mal écrit. Voir Les enums peuvent contenir des données.

C’est surtout important quand vous faites un match sur l’enum plus tard. La branche Shape::Circle { radius } => ... ne peut marcher que si chaque Circle a vraiment un radius. Si Rust laissait passer Shape::Circle { r: 2.0 }, cette garantie disparaîtrait. En attrapant la faute de frappe à la compilation, Rust s’assure que chaque Circle de votre programme est complet.

Choisissez-la quand rustc affiche available fields are ou a field with a similar name exists. Prenez le nom donné par l’indice. Les noms de champs sont sensibles à la casse et s’écrivent en snake_case : Radius et radius sont donc deux noms différents.

Une faute de frappe donne l’indice « similar name » :

error[E0559]: variant `Event::KeyPress` has no field named `kye`
--> src/main.rs:8:31
|
8 | let e = Event::KeyPress { kye: 'a' };
| ^^^ unknown field
|
help: a field with a similar name exists
|
8 - let e = Event::KeyPress { kye: 'a' };
8 + let e = Event::KeyPress { key: 'a' };
|

Ici, « unknown field » veut dire « champ inconnu », et la ligne + montre le code corrigé.

Un nom court comme r est trop différent de radius pour une suggestion, alors vous recevez la liste des champs à la place. Dans les deux cas, écrivez le champ que la variante définit :

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
#[derive(Debug)]
enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn main() {
let shapes = [
Shape::Circle { radius: 2.0 }, // ✅ le vrai nom du champ
Shape::Rectangle { width: 3.0, height: 4.0 },
];
for shape in &shapes {
println!("{:?}", shape);
}
let events = [Event::KeyPress { key: 'a' }, Event::Click { x: 10, y: 20 }];
println!("{:?}", events);
}

Sortie :

Circle { radius: 2.0 }
Rectangle { width: 3.0, height: 4.0 }
[KeyPress { key: 'a' }, Click { x: 10, y: 20 }]
▶ Essayez par vous-même

Attention à la syntaxe abrégée d’initialisation (field init shorthand). Shape::Circle { r } veut dire Shape::Circle { r: r }, et donne donc la même erreur E0559. Si votre variable s’appelle r, écrivez le champ en entier : Shape::Circle { radius: r }. Ou renommez la variable en radius et écrivez Shape::Circle { radius }.

Solution 2 : utiliser des parenthèses pour une variante tuple

Section intitulée « Solution 2 : utiliser des parenthèses pour une variante tuple »

Choisissez-la quand rustc dit is a tuple variant, use the appropriate syntax. Une variante comme Write(String) a bien un champ, mais ce champ n’a pas de nom. N’importe quel nom écrit entre accolades est donc faux :

error[E0559]: variant `Message::Write` has no field named `text`
--> src/main.rs:8:30
|
4 | Write(String),
| ----- `Message::Write` defined here
...
8 | let m = Message::Write { text: String::from("hi") };
| ^^^^ field does not exist
|
help: `Message::Write` is a tuple variant, use the appropriate syntax
|
8 - let m = Message::Write { text: String::from("hi") };
8 + let m = Message::Write(/* String */);
|

L’étiquette « field does not exist » veut dire « ce champ n’existe pas », et « defined here » montre où la variante est définie. Le /* String */ de la suggestion est un emplacement à remplir : mettez-y votre valeur. Créez une variante tuple avec des parenthèses, dans le même ordre que sa définition :

#[derive(Debug)]
enum Message {
Move { x: i32, y: i32 }, // champs nommés : on utilise { }
Write(String), // champ sans nom : on utilise ( )
Color(u8, u8, u8),
}
fn main() {
let messages = vec![
Message::Move { x: 1, y: 2 },
Message::Write(String::from("salut")), // ✅ des parenthèses
Message::Color(255, 128, 0),
];
for m in &messages {
match m {
Message::Move { x, y } => println!("déplacement vers ({}, {})", x, y),
Message::Write(text) => println!("écrire : {}", text),
Message::Color(r, g, b) => println!("couleur : {} {} {}", r, g, b),
}
}
}

Sortie :

déplacement vers (1, 2)
écrire : salut
couleur : 255 128 0
▶ Essayez par vous-même

Si vous préférez donner un nom au champ, changez la définition en Write { text: String }. Ensuite, Message::Write { text: ... } fonctionne. La confusion inverse, des parenthèses sur une variante à champs nommés comme Shape::Circle(2.0), donne une autre erreur : E0533, « expected value, found struct variant » (valeur attendue, variante de type struct trouvée).

Solution 3 : choisir la bonne variante, ou modifier la variante

Section intitulée « Solution 3 : choisir la bonne variante, ou modifier la variante »

Choisissez-la quand le champ que vous avez écrit existe, mais dans une autre variante. Ici, radius appartient à Circle, pas à Square :

error[E0559]: variant `Shape::Square` has no field named `radius`
--> src/main.rs:8:29
|
8 | let s = Shape::Square { radius: 2.0 };
| ^^^^^^ `Shape::Square` does not have this field
|
= note: available fields are: `side`

Demandez-vous laquelle vous vouliez. Pour un cercle, utilisez Shape::Circle { radius: 2.0 }. Pour un carré, utilisez son champ : Shape::Square { side: 2.0 }.

Si vous voyez note: all struct fields are already assigned, la variante est complète et votre champ est en trop. Supprimez-le ou, si votre code en a vraiment besoin, ajoutez-le à la définition de la variante :

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
#[derive(Debug)]
enum Message {
Move { x: i32, y: i32, z: i32 }, // `z` ajouté, parce que le code en a besoin
}
fn main() {
let a = Shape::Circle { radius: 2.0 }; // un cercle a un rayon
let b = Shape::Square { side: 2.0 }; // un carré a un côté
println!("{:?} et {:?}", a, b);
let m = Message::Move { x: 1, y: 2, z: 3 };
println!("{:?}", m);
}

Sortie :

Circle { radius: 2.0 } et Square { side: 2.0 }
Move { x: 1, y: 2, z: 3 }
▶ Essayez par vous-même

Dès que vous ajoutez un champ à une variante, chaque endroit qui crée cette variante doit aussi le remplir. rustc vous montrera chacun d’eux avec E0063, « missing field » (champ manquant).

Les méthodes constructeurs avec Self::. Dans impl Shape, écrire fn circle(r: f64) -> Shape { Self::Circle { r } } donne E0559 pour r, à cause de la syntaxe abrégée. Correction : Self::Circle { radius: r }. Voir Les enums peuvent aussi avoir des méthodes.

Après avoir renommé un champ. Vous avez renommé Circle { r } en Circle { radius } dans l’enum, et chaque ancien Shape::Circle { r: ... } donne maintenant E0559 avec available fields are: `radius`. Cherchez l’ancien nom dans tout le projet et mettez à jour chaque endroit.

Dans un pattern de match. Écrire le mauvais nom de champ dans un pattern, comme Shape::Circle { r } => ..., est la même erreur, mais rustc utilise d’autres codes : E0026, « variant Shape::Circle does not have a field named r » (la variante n’a pas de champ nommé r), avec help: `Shape::Circle` has a field named `radius`, plus E0027, « pattern does not mention field radius » (le pattern ne mentionne pas le champ radius). Correction : Shape::Circle { radius } => ..., ou Shape::Circle { radius: r } => ... pour garder le nom court. Voir Le pattern matching.

Petit quiz

1. Pour enum Message { Write(String) }, que doit devenir Message::Write { text: s } ?

2. Vous avez let r = 2.0; et vous écrivez Shape::Circle { r }, mais le champ s'appelle radius. Comment corriger ?

3. Shape::Square { radius: 2.0 } donne E0559, et la note ne liste que side. Que se passe-t-il ?

Score : 0 / 3