Les erreurs du compilateur Rust expliquées
Le compilateur Rust vous affiche une erreur en rouge et vous ne savez pas trop ce qu’il attend de vous ? Vous êtes au bon endroit. Tous les développeurs Rust voient ces erreurs, souvent plusieurs fois par jour. La bonne nouvelle : il n’y en a qu’une poignée que vous croiserez encore et encore, et une fois que vous les connaissez, elles ne font plus peur.
Chaque page ci-dessous prend un code d’erreur, montre le vrai message, l’explique avec des mots simples et vous donne des corrections que vous pouvez exécuter dans votre navigateur.
Les erreurs les plus courantes
Section intitulée « Les erreurs les plus courantes »Le compilateur écrit ses messages en anglais, quelle que soit la langue de votre système. La colonne du milieu reprend donc le texte exact que vous verrez dans votre terminal.
| Erreur | Ce que dit le compilateur | En clair |
|---|---|---|
| E0382 | borrow of moved value | Vous avez donné une valeur, puis vous avez essayé de vous en servir à nouveau |
| E0502 | cannot borrow as mutable because it is also borrowed as immutable | Vous modifiez quelque chose pendant que quelqu’un est encore en train de le lire |
| E0499 | cannot borrow as mutable more than once at a time | Deux endroits veulent modifier la même chose en même temps |
| E0308 | mismatched types | Vous avez donné un type alors qu’un autre était attendu |
| E0277 | the trait bound is not satisfied | Un type ne sait pas faire ce que vous lui demandez (afficher, comparer, additionner…) |
| E0106 | missing lifetime specifier | Rust ne peut pas savoir combien de temps une référence renvoyée reste valide |
| E0425 | cannot find value in this scope | Un nom est mal orthographié, ou utilisé en dehors du bloc où il existe |
| E0599 | no method named … found | La méthode n’existe pas sur ce type, ou son trait n’est pas importé |
| E0384 | cannot assign twice to immutable variable | Vous avez modifié une variable qui n’a pas été déclarée mut |
| E0596 | cannot borrow as mutable, as it is not declared as mutable | Vous avez voulu modifier quelque chose à travers une variable ou une référence qui n’est pas mut |
| E0597 | borrowed value does not live long enough | Une référence sert encore alors que la valeur vers laquelle elle pointe a disparu |
| E0515 | cannot return reference to local variable | Vous avez renvoyé une référence vers quelque chose qui est libéré à la fin de la fonction |
| E0373 | closure may outlive the current function, but it borrows … | Une closure (souvent un thread) emprunte une variable locale qui risque d’avoir disparu avant qu’elle ne s’exécute |
| E0369 | binary operation == cannot be applied to type … |
Votre type ne gère pas (encore) ==, <, + et compagnie |
| E0432 | unresolved import | Une ligne use désigne une crate, un module ou un élément introuvable |
| E0433 | cannot find type … in this scope (older: failed to resolve) | Un chemin comme HashMap::new() utilise un nom qui n’est pas importé ou qui n’existe pas |
| E0424 | self value is a keyword only available in methods with a self parameter |
Vous avez utilisé self dans une fonction qui ne prend pas self |
| E0061 | this function takes N arguments but M arguments were supplied | Vous avez passé trop ou pas assez d’arguments (Rust n’a pas d’arguments optionnels) |
| E0594 | cannot assign to p.hp, as p is not declared as mutable |
Vous avez modifié un champ ou une valeur derrière & sans accès mut |
| E0004 | non-exhaustive patterns: X not covered |
Votre match ne traite pas toutes les valeurs possibles |
| E0507 | cannot move out of x which is behind a shared reference |
Vous avez voulu prendre possession de quelque chose que vous aviez seulement emprunté |
| E0603 | function x is private |
Vous avez utilisé une fonction, une struct ou un module qui n’est pas pub |
| E0716 | temporary value dropped while borrowed | Vous avez gardé une référence vers une valeur jetée à la fin de la ligne |
| E0463 | can’t find crate for x |
Une crate (ou la bibliothèque standard d’une cible) n’est pas installée |
| E0368 | binary assignment operation += cannot be applied to type … |
Votre type ne gère pas +=, -= et compagnie |
| E0057 | this function takes N arguments but M were supplied (note: closure defined here) | Vous avez appelé une closure avec trop ou pas assez d’arguments |
| E0282 | type annotations needed | Rust n’arrive pas à deviner un type tout seul, vous devez donc l’indiquer |
| E0609 | no field x on type T |
Le nom du champ est mal orthographié, ou la valeur est enveloppée (par exemple dans une Option) |
| E0593 | closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments | Une closure prend des arguments séparés là où un tuple (ou un autre nombre d’arguments) est attendu |
| E0631 | type mismatch in closure arguments | Le type d’un paramètre de closure ne correspond pas à ce qu’elle reçoit (souvent i32 contre &i32) |
| E0005 | refutable pattern in local binding | let Some(x) = … peut échouer, donc un simple let ne l’accepte pas |
| E0615 | attempted to take value of method len on type String |
Vous avez écrit s.len au lieu de s.len() |
| E0610 | {integer} is a primitive type and therefore doesn’t have fields |
Vous avez utilisé .champ sur un nombre, un bool ou un char |
| E0560 | struct User has no field named nmae |
La création d’une struct utilise un nom de champ que la struct n’a pas |
| E0616 | field balance of struct Account is private |
Vous lisez un champ qui n’est pas pub depuis l’extérieur de son module |
| E0451 | field x of struct Y is private |
Vous créez une struct avec un littéral alors que certains de ses champs sont privés |
| E0624 | method x is private |
Vous appelez une méthode ou une fonction associée qui n’est pas pub |
| E0283 | type annotations needed (cannot infer type … multiple impls satisfy this bound) | Plusieurs types pourraient convenir (par exemple pour .collect() ou .sum()), vous devez donc en choisir un |
| E0284 | type annotations needed: cannot satisfy <_ as FromStr>::Err == _ |
"42".parse() ne sait pas vers quel type convertir |
| E0790 | cannot call associated function on trait without specifying the corresponding impl type |
Vous avez écrit Default::default() ou Trait::new() sans dire de quel type il s’agit |
| E0559 | variant Shape::Circle has no field named r |
La création d’une variante d’enum utilise un nom de champ que cette variante n’a pas |
| E0063 | missing field email in initializer of User |
Vous avez créé une struct en oubliant un ou plusieurs champs |
| E0689 | can’t call method pow on ambiguous numeric type {integer} |
2.pow(10) ou 2.0.sqrt() a besoin d’un type de nombre précis, comme i32 ou f64 |
| E0034 | multiple applicable items in scope | Deux traits donnent à votre type une méthode du même nom, et Rust ne peut pas choisir |
| E0412 | cannot find type X in this scope (Rust 1.93+ prints E0425) |
Un nom de type est mal écrit, pas importé ou pas déclaré |
| E0428 | the name area is defined multiple times |
Deux éléments portent le même nom ; Rust n’a pas de surcharge de fonctions |
| E0026 | variant Shape::Circle does not have a field named r |
Un pattern nomme un champ que la struct ou la variante n’a pas |
| E0027 | pattern does not mention fields id, paid |
Un pattern de struct oublie des champs ; ajoutez-les ou terminez par .. |
| E0533 | expected unit struct, unit variant or constant, found struct variant Shape::Circle |
Une variante struct (ou une fonction) est utilisée là où un simple nom est attendu ; ajoutez { .. } |
| E0592 | duplicate definitions with name reset |
Deux blocs impl définissent une méthode du même nom |
| E0255 | the name Error is defined multiple times |
Un import use porte le même nom que votre propre type ou fonction |
| E0252 | the name Result is defined multiple times |
Deux lignes use importent le même nom ; renommez-en une avec as |
| E0411 | cannot find type Self in this scope |
Vous avez utilisé Self en dehors d’un impl ou d’un trait |
| E0405 | cannot find trait Display in this scope |
Un nom de trait est mal écrit ou pas importé (par ex. use std::fmt::Display;) |
| E0532 | expected unit struct, unit variant or constant, found tuple variant Shape::Circle |
Un motif nomme une variante tuple (ou une struct tuple) sans ses ( ), ou ajoute des ( ) là où il n’en faut pas |
| E0164 | expected tuple struct or tuple variant, found struct variant Shape::Circle |
Un motif met des ( ) sur une variante struct ou un élément associé ; utilisez des { } ou une garde |
| E0404 | expected trait, found derive macro Debug |
Vous avez écrit impl X for ou T: X alors que X est une struct, un alias ou une macro derive dont le trait n’est pas importé |
| E0401 | can’t use generic parameters from outer item | Une fn interne utilise le T ou le Self de la fonction extérieure ; donnez-lui ses propres génériques ou utilisez une closure |
| E0107 | enum takes 2 generic arguments but 1 generic argument was supplied | Result<u32>, HashMap<String> et compagnie : trop ou trop peu d’arguments entre < > |
| E0530 | match bindings cannot shadow tuple variants | Un nom de variante seul, comme Circle => (après use Shape::*), ne peut pas devenir une nouvelle variable |
| E0434 | can’t capture dynamic environment in a fn item | Une fn imbriquée ne voit pas les variables locales extérieures ; utilisez une closure ou passez-les en paramètre |
| E0601 | main function not found in crate main |
Le binaire n’a pas de fn main() (absente, mal orthographiée, cachée dans un mod, ou c’est en fait une bibliothèque) |
| E0658 | use of unstable library feature iter_intersperse |
Vous utilisez une API réservée à nightly sur Rust stable ; prenez l’alternative stable ou mettez Rust à jour |
| E0614 | type u32 cannot be dereferenced |
Vous avez écrit *x alors que x est déjà une simple valeur, pas une référence |
| E0435 | attempt to use a non-constant value in a constant | Une const, une taille de tableau ou un static utilise une variable let ; faites-en une const ou utilisez un Vec |
| E0554 | #![feature] may not be used on the stable release channel |
Du code copié réservé à nightly ; supprimez l’attribut et utilisez l’API stable, ou passez à nightly exprès |
Comment lire une erreur Rust
Section intitulée « Comment lire une erreur Rust »Les messages d’erreur de Rust sont réputés pour être utiles, mais ils contiennent beaucoup d’informations. En voici un vrai :
fn main() { let name = String::from("Ferris"); let greeting = name; println!("{name}");}error[E0382]: borrow of moved value: `name` --> src/main.rs:4:16 |2 | let name = String::from("Ferris"); | ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait3 | let greeting = name; | ---- value moved here4 | println!("{name}"); | ^^^^ value borrowed here after move |help: consider cloning the value if the performance cost is acceptable |3 | let greeting = name.clone(); | ++++++++Lisez-le dans cet ordre :
- La première ligne est le résumé : le code d’erreur (
E0382) et une description en une ligne (ici « emprunt d’une valeur déplacée »). - La ligne avec la flèche (
--> src/main.rs:4:16) vous donne le fichier, la ligne et la colonne où le problème se trouve. - Les marques
^^^^pointent l’endroit exact de l’erreur. Les marques----racontent ce qui s’est passé avant. Ici, elles disent : la valeur a été créée à la ligne 2, déplacée (moved) à la ligne 3, puis utilisée à la ligne 4. help:est la correction proposée par le compilateur, souvent avec le code exact à ajouter (les marques++++montrent les nouveaux caractères). Ce n’est pas toujours la meilleure solution, mais c’est un excellent point de départ.
Commencez toujours par la première erreur. Une seule faute peut provoquer toute une série d’erreurs en cascade, et corriger la première fait souvent disparaître les autres.
Trois habitudes qui aident
Section intitulée « Trois habitudes qui aident »-
Demandez plus d’explications au compilateur. Chaque code d’erreur a une explication détaillée intégrée. Lancez ceci dans un terminal :
Terminal window rustc --explain E0382Vous obtenez une courte description, un exemple qui ne compile pas et sa version corrigée (en anglais).
-
Vérifiez souvent.
cargo checktrouve les erreurs sans construire tout le programme, c’est donc beaucoup plus rapide quecargo build. En le lançant toutes les quelques lignes, vous rencontrez les erreurs une par une, pas vingt d’un coup. Voir Cargo et les crates. -
Laissez votre éditeur afficher les erreurs pendant que vous tapez. Avec l’extension rust-analyzer, les erreurs apparaissent directement dans votre code, avec le même texte d’aide. Voir Les outils de Rust.
Pourquoi Rust a autant d’erreurs
Section intitulée « Pourquoi Rust a autant d’erreurs »La plupart de ces erreurs existent parce que Rust vérifie, avant que votre programme ne tourne, des choses que d’autres langages ne découvrent qu’à l’exécution (ou jamais) : utiliser de la mémoire déjà libérée, deux threads qui modifient les mêmes données, un test de null oublié. Chaque erreur que vous corrigez est un bug qui n’atteindra jamais vos utilisateurs.
C’est pour ça que beaucoup de gens disent : en Rust, la bagarre a lieu à la compilation, et ensuite le programme fonctionne, tout simplement. Les règles derrière les erreurs les plus fréquentes sont expliquées dans L’ownership, Le borrowing et Les lifetimes.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. Une erreur Rust affiche plusieurs problèmes. Lequel faut-il corriger en premier ?
2. Que fait rustc --explain E0382 ?
3. Dans un message d'erreur, que montrent les marques ^^^^ ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Rust Compiler Error Index (en anglais) : la liste officielle de tous les codes d’erreur, chacun avec un exemple cassé et un exemple corrigé.
- Understanding Ownership — The Rust Book (en anglais) : les règles derrière les erreurs d’emprunt et de déplacement les plus courantes.
- Error Handling — The Rust Book (en anglais) : comment Rust gère les erreurs dans vos propres programmes (
Resultetpanic!), et pas seulement les erreurs du compilateur. - What is rustc? — The rustc Book (en anglais) : comment fonctionne le compilateur, avec ses options et ses niveaux de lints.