Erreur Rust E0560 : struct has no field named X (champ inconnu)
E0560 veut dire : vous créez une struct avec Name { field: value }, et l’un des champs que vous avez écrits n’existe pas dans cette struct. En général, c’est une faute de frappe, un champ qui a été renommé, ou un champ qui appartient à une autre struct. rustc vous indique souvent le nom exact que vous vouliez écrire : c’est donc l’une des erreurs les plus rapides à corriger. (Cette page fait partie de Les erreurs du compilateur Rust expliquées.)
Le message d’erreur
Section intitulée « Le message d’erreur »error[E0560]: struct `User` has no field named `nmae` --> src/main.rs:9:9 |9 | nmae: String::from("Ferris"), // ❌ typo: the field is `name` | ^^^^ unknown field |help: a field with a similar name exists |9 - nmae: String::from("Ferris"), // ❌ typo: the field is `name`9 + name: String::from("Ferris"), // ❌ typo: the field is `name` |Le compilateur vous dit : « la struct User n’a pas de champ nommé nmae ». L’étiquette « unknown field » veut dire « champ inconnu », et l’aide « a field with a similar name exists » vous signale qu’un champ au nom proche existe, puis vous montre la ligne corrigée.
Voici le programme qui la provoque :
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { nmae: String::from("Ferris"), // ❌ typo: the field is `name` active: true, }; println!("{}", user.email);}(Le commentaire dit : faute de frappe, le champ s’appelle name.)
Ce que ça veut dire
Section intitulée « Ce que ça veut dire »Le titre nomme la struct (User) et le champ que vous avez écrit (nmae). Les ^^^^ pointent ce champ à l’intérieur du bloc User { ... }. Rust l’a comparé à la liste des champs de struct User et n’a trouvé aucune correspondance.
Sous la flèche, vous aurez l’un de ces trois indices. Chacun vous apprend quelque chose de différent :
help: a field with a similar name exists(un champ au nom proche existe) : une faute de frappe. rustc montre la ligne avec le bon nom.note: available fields are: `username`(champs disponibles :username) : aucun nom proche. Ce sont les champs que vous n’avez pas encore remplis.note: all struct fields are already assigned(tous les champs de la struct sont déjà remplis) : vous avez rempli tous les vrais champs, et celui-ci est en trop.
Remarquez que rustc ne se plaint pas en plus de l’absence de name. Corrigez la faute de frappe, et les deux problèmes disparaissent d’un coup.
C’est comme remplir un formulaire papier et écrire votre numéro de téléphone dans une case « Fax ». Le formulaire n’a pas cette case, alors le guichetier vous le rend.
Pourquoi Rust fait ça
Section intitulée « Pourquoi Rust fait ça »Les champs d’une struct sont fixés au moment où vous écrivez struct User { ... }. Chaque fois que vous créez un User, Rust vérifie que vous avez donné exactement ces champs : aucun qui manque, aucun en trop, aucun mal écrit. Voir Définir et créer une struct.
Cela attrape de vrais bugs. En JavaScript, { nmae: "Ferris" } crée sans rien dire un objet avec la mauvaise clé, et user.name vaut undefined bien plus loin dans le programme. En Rust, la faute de frappe ne passe pas le compilateur : chaque User de votre programme a donc vraiment un name.
Comment corriger
Section intitulée « Comment corriger »Solution 1 : corriger l’orthographe
Section intitulée « Solution 1 : corriger l’orthographe »Choisissez-la quand vous voyez a field with a similar name exists. Prenez le nom indiqué dans la ligne help:. Les noms de champs sont sensibles à la casse, et Rust utilise le snake_case : userName et user_name sont donc deux noms différents.
Attention aussi à la syntaxe abrégée d’initialisation (field init shorthand) : User { nmae, email } veut dire User { nmae: nmae, email: email }, le nom de la variable doit donc être le même que celui du champ. Renommez la variable, ou écrivez le champ en entier : User { name: nmae, email }.
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { name: String::from("Ferris"), // ✅ le vrai nom du champ active: true, }; println!("{} ({}) actif : {}", user.name, user.email, user.active);
// syntaxe abrégée : les noms des variables sont ceux des champs let name = String::from("Ada"); let other = User { name, email, active: false }; println!("{} ({}) actif : {}", other.name, other.email, other.active);}Sortie :
Ferris ([email protected]) actif : trueAda ([email protected]) actif : falseSolution 2 : utiliser le nouveau nom du champ, ou ajouter le champ
Section intitulée « Solution 2 : utiliser le nouveau nom du champ, ou ajouter le champ »Choisissez-la quand il n’y a pas d’indice « similar name ». Souvent, la struct a changé : quelqu’un a renommé name en username, ou un champ a été supprimé, mais ce code utilise encore l’ancien. rustc liste ce qui reste :
error[E0560]: struct `User` has no field named `name` --> src/main.rs:8:9 |8 | name: String::from("Ferris"), | ^^^^ `User` does not have this field | = note: available fields are: `username`Ici, l’étiquette dit « User n’a pas ce champ », et la note donne les champs disponibles.
Vous avez deux choix honnêtes. Si la struct est correcte, utilisez le nom actuel du champ. Si c’est votre code qui a raison et que la struct a vraiment besoin de ce champ, ajoutez-le à la définition de la struct. Ici, Config donnait all struct fields are already assigned pour debug, et la solution est d’ajouter debug à la struct :
struct User { username: String, // renommé depuis `name` : on utilise le nouveau nom email: String,}
struct Config { port: u16, host: String, debug: bool, // ajouté à la struct, parce que le code en a besoin}
fn main() { let user = User { username: String::from("ferris"), }; println!("{} ({})", user.username, user.email);
let config = Config { port: 8080, host: String::from("localhost"), debug: true, }; println!("{}:{} debug={}", config.host, config.port, config.debug);}Sortie :
ferris ([email protected])localhost:8080 debug=trueSi la struct vient d’une crate (bibliothèque) que vous venez de mettre à jour, le champ a peut-être été renommé dans la nouvelle version. Consultez la struct sur docs.rs pour cette version, ou le changelog de la crate. Dès que vous ajoutez un champ à votre propre struct, chaque endroit qui la crée doit aussi le remplir. rustc vous montrera chacun d’eux avec E0063 (voir plus bas).
Solution 3 : utiliser la bonne struct
Section intitulée « Solution 3 : utiliser la bonne struct »Choisissez-la quand le champ que vous avez écrit existe, mais dans une autre struct. Avec deux structs qui se ressemblent, comme un Product avec un title et un Customer avec un name, on les confond facilement :
error[E0560]: struct `Product` has no field named `name` --> src/main.rs:13:9 |13 | name: String::from("Keyboard"), | ^^^^ `Product` does not have this field | = note: available fields are: `title`Regardez la note available fields. Si elle liste des champs auxquels vous ne vous attendiez pas, vous êtes en train de construire la mauvaise struct. Utilisez le bon nom de struct, ou le nom de champ de la struct que vous vouliez :
struct Product { title: String, price: u32, // en centimes}
struct Customer { name: String, email: String,}
fn main() { let keyboard = Product { title: String::from("clavier"), // les produits ont un `title` price: 4900, }; let buyer = Customer { name: String::from("Ana"), // les clients ont un `name` }; println!("{} achète un {} pour {} centimes", buyer.name, keyboard.title, keyboard.price); println!("Reçu envoyé à {}", buyer.email);}Sortie :
Ana achète un clavier pour 4900 centimesReçu envoyé à [email protected]Solution 4 : utiliser des parenthèses pour une tuple struct
Section intitulée « Solution 4 : utiliser des parenthèses pour une tuple struct »Choisissez-la quand la struct est une tuple struct, comme struct Point(i32, i32);. Ses champs n’ont pas de nom, donc Point { x: 1, y: 2 } donne E0560 pour x et pour y, avec help: `Point` is a tuple struct, use the appropriate syntax (Point est une tuple struct, utilisez la syntaxe adaptée) et la suggestion Point(/* i32 */, /* i32 */). Créez-la avec des parenthèses, Point(1, 2), et lisez-la avec .0 et .1. Si vous préférez des noms, changez la définition en struct Point { x: i32, y: i32 }. Voir Tuple ou struct ?
L’inverse : E0063, champ manquant
Section intitulée « L’inverse : E0063, champ manquant »La jumelle de E0560, c’est E0063 : un champ que la struct possède, mais que vous n’avez pas rempli. Rust ne remplit jamais les champs à votre place, chaque champ a donc besoin d’une valeur :
error[E0063]: missing field `active` in initializer of `User` --> src/main.rs:8:16 |8 | let user = User { | ^^^^ missing `active`Le message veut dire « champ active manquant dans l’initialisation de User ». S’il manque plusieurs champs, il les liste tous : missing fields `active`, `email` and `login_count` in initializer of `User`. Correction : donnez une valeur à chaque champ. Si beaucoup de champs ont une valeur par défaut raisonnable, dérivez Default et utilisez la syntaxe de mise à jour (struct update syntax) .. pour remplir le reste :
#[derive(Debug, Default)]struct Settings { volume: u8, dark_mode: bool, language: String,}
fn main() { // tous les champs écrits en entier let full = Settings { volume: 80, dark_mode: false, language: String::from("fr") };
// seulement les champs qui vous intéressent, le reste vient de Default let quick = Settings { dark_mode: true, ..Default::default() };
// on copie le reste depuis une autre valeur let louder = Settings { volume: 100, ..full };
println!("{:?}", quick); println!("{:?}", louder);}Sortie :
Settings { volume: 0, dark_mode: true, language: "" }Settings { volume: 100, dark_mode: false, language: "fr" }La valeur par défaut d’un nombre est 0, celle d’un bool est false, et celle d’une String est la chaîne vide. Si vous voulez d’autres valeurs par défaut, écrivez vous-même impl Default for Settings. Voir Default : une valeur de départ raisonnable.
Où vous le verrez souvent
Section intitulée « Où vous le verrez souvent »Dans la syntaxe de mise à jour ... Settings { dark: true, ..defaults } donne aussi E0560. Ici, la note liste tous les champs (available fields are: `volume`, `dark_mode`, `language`), et il peut n’y avoir aucun indice « similar name » quand les noms sont trop différents. Correction : dark_mode: true.
Les variantes d’enum avec des champs nommés. Pour enum Shape { Circle { radius: f64 } }, écrire Shape::Circle { r: 2.0 } est la même erreur, mais rustc utilise un autre code : E0559, variant `Shape::Circle` has no field named `r` (la variante Shape::Circle n’a pas de champ nommé r), avec la même note available fields et les mêmes indices de faute de frappe. Correction : Shape::Circle { radius: 2.0 }. Voir Les enums peuvent contenir des données.
Une struct venant d’un autre module. Si le champ existe mais n’est pas pub, vous obtenez à la place E0451, « field balance of struct Account is private » (le champ balance de Account est privé). Correction : utilisez le constructeur du module, comme Account::new(...). Voir Tout est privé par défaut.
Erreurs liées
Section intitulée « Erreurs liées »- E0609 : no field
xon typeT: la même faute de frappe, mais en lisant un champ (user.nmae) au lieu de créer la struct. - E0451 : field is private in struct literal : le champ existe, mais vous ne pouvez pas le remplir depuis cet endroit.
- E0308 : mismatched types : le nom du champ est bon, mais la valeur n’a pas le bon type, comme
"Ferris"pour un champString. E0063: missing field in initializer: un champ que vous avez oublié (voir plus haut).E0559: variant has no field named x: l’équivalent de E0560 pour les variantes d’enum.- Toutes les erreurs du compilateur expliquées
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. rustc affiche note: all struct fields are already assigned. Qu'est-ce que ça veut dire ?
2. Vous avez let nmae = ...; et vous écrivez User { nmae, email }. Comment corriger ?
3. Quelle erreur obtenez-vous si vous oubliez un champ, comme User { name, email } sans active ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- E0560 — Rust error codes index (en anglais) : l’explication officielle de cette erreur.
- Defining and Instantiating Structs — The Rust Book (en anglais) : les littéraux de struct, la syntaxe abrégée d’initialisation, la syntaxe de mise à jour et les tuple structs.
- E0063 — Rust error codes index (en anglais) : la page officielle de la jumelle « champ manquant » de cette erreur.
- Struct expressions — The Rust Reference (en anglais) : les règles exactes de
Name { field: value }, de la syntaxe abrégée et de..base. Default— documentation de la bibliothèque standard (en anglais) : comment fonctionnent#[derive(Default)]et..Default::default().