Aller au contenu

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.

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

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` trait
3 | let greeting = name;
| ---- value moved here
4 | 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 :

  1. 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 »).
  2. 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.
  3. 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.
  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.

  • 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 E0382

    Vous obtenez une courte description, un exemple qui ne compile pas et sa version corrigée (en anglais).

  • Vérifiez souvent. cargo check trouve les erreurs sans construire tout le programme, c’est donc beaucoup plus rapide que cargo 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.

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

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