Aller au contenu

Erreur Rust E0027 : pattern does not mention field X (champ oublié dans un motif)

E0027 veut dire que vous décomposez une struct ou une variante d’enum avec un motif (pattern), comme let Order { item, quantity } = order;, et que vous n’avez pas mentionné tous les champs. En Rust, un motif de struct doit tenir compte de tous les champs, soit en les nommant, soit en disant « et le reste » avec ... C’est l’une des erreurs les plus sympathiques qui soient : rustc affiche la correction exacte, et c’est presque toujours deux points. Cette page fait partie du guide des erreurs du compilateur Rust.

error[E0027]: pattern does not mention fields `id`, `paid`
--> src/main.rs:10:9
|
10 | let Order { item, quantity } = order; // ❌ `id` et `paid` ne sont pas mentionnés
| ^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `id`, `paid`
|
help: include the missing fields in the pattern
|
10 | let Order { item, quantity, id, paid } = order; // ❌ `id` et `paid` ne sont pas mentionnés
| ++++++++++
help: if you don't care about these missing fields, you can explicitly ignore them
|
10 | let Order { item, quantity, id: _, paid: _ } = order; // ❌ `id` et `paid` ne sont pas mentionnés
| ++++++++++++++++
help: or always ignore missing fields here
|
10 | let Order { item, quantity, .. } = order; // ❌ `id` et `paid` ne sont pas mentionnés
| ++++

Le compilateur vous dit : « le motif ne mentionne pas les champs id et paid ». La section « Ce que ça veut dire » ci-dessous explique les trois suggestions.

Voici le programme qui la provoque :

struct Order {
id: u32,
item: String,
quantity: u32,
paid: bool,
}
fn main() {
let order = Order { id: 1, item: String::from("clavier"), quantity: 2, paid: true };
let Order { item, quantity } = order; // ❌ `id` et `paid` ne sont pas mentionnés
println!("{} x {}", quantity, item);
}

Le titre de l’erreur liste les champs que votre motif a oubliés (id et paid). Le ^^^ souligne tout le motif, car le problème n’est pas un mot faux, mais quelque chose qui manque.

rustc donne ensuite trois suggestions help:. Elles sont toutes valables, et elles ne veulent pas dire la même chose :

  • include the missing fields (inclure les champs manquants) : nommez-les, et vous obtenez aussi des variables id et paid.
  • explicitly ignore them (les ignorer explicitement) : écrivez id: _, paid: _. Vous n’obtenez pas de variables, mais vous avez listé chaque champ par son nom.
  • always ignore missing fields here (toujours ignorer les champs manquants ici) : écrivez ... Ça veut dire « et tous les autres champs, ils ne m’intéressent pas ».

C’est comme une liste de contrôle à l’entrée qui dit « cochez chaque case, ou cochez Autre : passer ». Vous ne pouvez pas simplement laisser des cases vides.

En Rust, un motif de struct est censé être complet, sauf si vous dites le contraire. Ça rend votre intention claire pour la personne qui lira le code ensuite. Order { item, quantity, .. } dit « je n’ai besoin que de ces deux-là ». Order { id, item, quantity, paid } dit « j’ai pensé à chaque champ ». Voir Ignorer des parties avec _ et ...

Le vrai bénéfice arrive quand la struct change. Si quelqu’un ajoute un champ discount à Order, un motif qui liste chaque champ par son nom casse avec E0027, et vous montre ainsi du code qui doit peut-être gérer le nouveau champ. Un motif avec .. continue de compiler. Rust vous laisse choisir le comportement que vous voulez, mais il ne devine pas à votre place.

Choisissez-la la plupart du temps. Si vous n’avez besoin que de certains champs, terminez le motif par ... Ça marche dans let, match, if let et les paramètres de fonction, et .. doit venir en dernier.

struct Order {
id: u32,
item: String,
quantity: u32,
paid: bool,
}
fn main() {
let order = Order { id: 1, item: String::from("clavier"), quantity: 2, paid: true };
let Order { item, quantity, .. } = order; // ✅ `..` saute `id` et `paid`
println!("{} x {}", quantity, item);
let orders = [
Order { id: 2, item: String::from("souris"), quantity: 1, paid: false },
Order { id: 3, item: String::from("écran"), quantity: 1, paid: true },
];
for order in &orders {
match order {
Order { paid: true, item, .. } => println!("expédier : {}", item),
Order { id, .. } => println!("la commande n°{} attend le paiement", id),
}
}
}

Sortie :

2 x clavier
la commande n°2 attend le paiement
expédier : écran
▶ Essayez par vous-même

Remarquez paid: true dans la première branche : un champ d’un motif peut aussi être comparé à une valeur, et .. s’occupe toujours des autres.

Solution 2 : nommer le champ manquant, ou l’ignorer par son nom avec _

Section intitulée « Solution 2 : nommer le champ manquant, ou l’ignorer par son nom avec _ »

Choisissez-la quand vous avez vraiment besoin du champ, ou quand vous voulez que le motif casse si un champ est ajouté plus tard. La même erreur apparaît dans un match sur une variante d’enum à champs nommés :

error[E0027]: pattern does not mention field `y`
--> src/main.rs:9:9
|
9 | Message::Move { x } => println!("aller en x = {}", x), // ❌ `y` n'est pas mentionné
| ^^^^^^^^^^^^^^^^^^^ missing field `y`

Le programme qui la provoque :

enum Message {
Move { x: i32, y: i32 },
Quit,
}
fn main() {
let m = Message::Move { x: 1, y: 2 };
match m {
Message::Move { x } => println!("aller en x = {}", x), // ❌ `y` n'est pas mentionné
Message::Quit => println!("quitter"),
}
}

Un déplacement a deux coordonnées, et le code devrait vraiment utiliser les deux. Nommez donc y. Quand un champ n’a vraiment aucune importance, y: _ le dit clairement, tout en le listant par son nom :

enum Message {
Move { x: i32, y: i32 },
Quit,
}
fn main() {
let messages = [Message::Move { x: 1, y: 2 }, Message::Move { x: 5, y: 0 }, Message::Quit];
for m in &messages {
match m {
Message::Move { x, y: 0 } => println!("glisser au sol jusqu'à x = {}", x),
Message::Move { x, y } => println!("aller en ({}, {})", x, y), // ✅ les deux champs
Message::Quit => println!("quitter"),
}
}
// chaque champ listé par son nom : ajouter un champ à `Move` cassera ce code, exprès
if let Message::Move { x, y: _ } = &messages[0] {
println!("premier x = {}", x);
}
}

Sortie :

aller en (1, 2)
glisser au sol jusqu'à x = 5
quitter
premier x = 1
▶ Essayez par vous-même

Si vous nommez un champ juste pour l’ignorer, écrivez y: _, pas un simple y. Un y que vous n’utilisez jamais donne un avertissement « unused variable » (variable inutilisée).

Choisissez-la quand E0027 arrive en même temps que E0026 sur la même ligne. Par exemple, Shape::Circle { r } pour une variante dont le champ s’appelle radius donne les deux : E0026 pour r (ce champ n’existe pas) et E0027 pour radius (pas mentionné). L’aide de rustc pour E0027 vous proposera d’ajouter radius à côté de r, mais ce n’est pas ce que vous voulez. La vraie correction est de remplacer le mauvais nom : Shape::Circle { radius }, ou Shape::Circle { radius: r } pour garder le nom de variable court. Les deux erreurs disparaissent alors d’un coup. Voir la page E0026 pour des exemples.

Après avoir ajouté un champ à une struct. Vous ajoutez created_at à Order, et chaque motif qui listait tous les champs donne maintenant E0027. C’est la vérification qui fait son travail. Décidez au cas par cas : ce code a-t-il besoin de created_at ? Si oui, nommez-le ; sinon, ajoutez ...

Les paramètres de fonction. fn print_order(&Order { item, quantity }: &Order) donne aussi E0027. Correction : &Order { item, quantity, .. }. Voir Les motifs dans let et dans les paramètres de fonction.

Les structs tuples et les variantes tuples. Pour struct Color(u8, u8, u8);, le motif Color(r) est lui aussi incomplet, mais rustc le signale avec E0023, « this pattern has 1 field, but the corresponding tuple struct has 3 fields » (ce motif a 1 champ, mais la struct tuple correspondante en a 3). La correction suit la même idée : Color(r, ..) ou Color(r, _, _).

Petit quiz

1. struct Point { x: i32, y: i32, z: i32 }. Quel motif compile et ne vous donne que x ?

2. Quelle est la différence entre Order { item, .. } et Order { item, id: _, quantity: _, paid: _ } ?

3. Vous obtenez E0026 pour r et E0027 pour radius sur la même ligne. Quelle est la meilleure correction ?

Score : 0 / 3