Erreur Rust E0599 : no method named X found (méthode introuvable)
L’erreur E0599 veut dire que vous avez appelé une méthode que Rust ne trouve pas sur ce type. Elle est très fréquente, et la cause est presque toujours l’une de ces quelques situations : un trait que vous n’avez pas importé, un Option que vous n’avez pas déballé, un Vec utilisé comme s’il était un itérateur, ou une simple faute de frappe. Bonne nouvelle : les lignes help: de rustc vous donnent souvent la correction exacte. Cette page fait partie du guide des erreurs du compilateur Rust.
Le message d’erreur
Section intitulée « Le message d’erreur »error[E0599]: no method named `write_all` found for struct `Stdout` in the current scope --> src/main.rs:5:9 |5 | out.write_all(b"Server started\n").unwrap(); | ^^^^^^^^^ | = note: the method is available for `Stdout` here | = help: items from traits can only be used if the trait is in scopehelp: trait `Write` which provides `write_all` is implemented but not in scope; perhaps you want to import it |1 + use std::io::Write; |Le compilateur vous dit : « aucune méthode nommée write_all trouvée pour la struct Stdout dans la portée actuelle ». Il précise que les méthodes d’un trait ne sont utilisables que si ce trait est importé, et vous propose la ligne use std::io::Write;.
Voici le programme qui la provoque :
use std::io;
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}Ce que ça veut dire
Section intitulée « Ce que ça veut dire »Les ^^^^ désignent le nom de la méthode, write_all, et la première ligne vous dit sur quel type Rust a cherché : Stdout. Le message signifie donc : « J’ai regardé Stdout et je n’ai trouvé aucune méthode appelée write_all que j’ai le droit d’utiliser ici. »
Le type indiqué dans cette première ligne est l’indice le plus utile de tout le message. S’il affiche Option<T>, Result<T, E>, Vec<_> ou un paramètre de type T alors que vous attendiez autre chose, vous savez déjà quelle solution ci-dessous il vous faut.
Pourquoi Rust fait ça
Section intitulée « Pourquoi Rust fait ça »En Rust, beaucoup de méthodes n’appartiennent pas au type lui-même. Elles viennent d’un trait. write_all vient du trait Write, et Stdout l’implémente. Mais les méthodes d’un trait ne fonctionnent que dans un fichier où ce trait est dans la portée, en général grâce à une ligne use. C’est le sens de « items from traits can only be used if the trait is in scope ».
Cette règle rend le code prévisible. Deux crates peuvent chacune ajouter une méthode write_all au même type, à travers deux traits différents. Si tous les traits étaient toujours actifs, impossible de savoir lequel un appel désigne. Avec la règle, seuls les traits que vous avez importés comptent.
Les autres causes viennent des types stricts de Rust. Un Option<&str> n’est pas un &str, il n’a donc pas les méthodes de &str. Un type générique T peut être n’importe quel type, alors Rust ne vous laisse appeler que les méthodes promises par les contraintes (bounds) sur T.
Comment corriger
Section intitulée « Comment corriger »Solution 1 : importer le trait
Section intitulée « Solution 1 : importer le trait »Choisissez-la quand l’aide dit « items from traits can only be used if the trait is in scope ». Ajoutez la ligne use que rustc propose.
use std::io::{self, Write};
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}Sortie :
Server started(Le message reste en anglais ici : une chaîne d’octets b"..." n’accepte que des caractères ASCII, donc pas d’accents.)
C’est la même chose avec la crate rand. Sans l’import, rng.random_range(1..=6) échoue, et rustc vous dit quel trait importer :
help: trait `RngExt` which provides `random_range` is implemented but not in scope; perhaps you want to import it |1 + use rand::RngExt;Attention : dans rand 0.10, le trait s’appelle RngExt. Les anciens tutoriels disent use rand::Rng, et avec rand 0.10 cet import vous donne exactement la même erreur. Suivez la ligne help:, pas le tutoriel.
Solution 2 : sortir d’abord la valeur de l’Option ou du Result
Section intitulée « Solution 2 : sortir d’abord la valeur de l’Option ou du Result »Choisissez-la quand le type dans l’erreur est Option<T> ou Result<T, E>. La valeur que vous voulez est à l’intérieur, et vous devez l’en sortir avant d’appeler ses méthodes.
error[E0599]: no method named `to_uppercase` found for enum `Option<T>` in the current scope --> src/main.rs:4:39 |4 | println!("First guest: {}", first.to_uppercase()); | ^^^^^^^^^^^^ method not found in `Option<&&str>`Rustc indique que la méthode n’existe pas sur Option<&&str>. first() renvoie un Option, car la liste pourrait être vide. Rustc propose .expect(...), qui marche mais plante sur None. Il vaut généralement mieux gérer les deux cas :
fn main() { let guests = vec!["ana", "bo", "chen"];
match guests.first() { Some(name) => println!("Premier invité : {}", name.to_uppercase()), None => println!("Pas encore d'invités"), }
let shout = guests.last().map(|name| name.to_uppercase()); println!("Dernier invité : {:?}", shout);}Sortie :
Premier invité : ANADernier invité : Some("CHEN").map() exécute votre code sur la valeur intérieure et garde l’enveloppe Option. Pour un Result (par exemple celui de .parse()), utilisez match, .unwrap_or(...), ou ? dans une fonction qui renvoie un Result. Voir Option et Result.
Solution 3 : appeler .iter() sur le Vec
Section intitulée « Solution 3 : appeler .iter() sur le Vec »Choisissez-la quand vous appelez .map(), .filter() ou une autre méthode d’itérateur directement sur un Vec. L’erreur a alors une autre allure :
error[E0599]: the method `map` exists for struct `Vec<{integer}>`, but its trait bounds were not satisfied --> src/main.rs:3:35 |3 | let curved: Vec<i32> = scores.map(|s| s + 5).collect(); | ^^^ | = note: the following trait bounds were not satisfied: `Vec<{integer}>: Iterator`Rustc dit que la méthode map existe pour Vec<{integer}>, mais que ses contraintes de trait ne sont pas respectées. Pour certaines méthodes, comme filter, le message est plus clair : rustc dit que le Vec<i32> « is not an iterator » (n’est pas un itérateur) et ajoute help: call `.into_iter()` first. Même cause, même correction.
Vec<{integer}>: Iterator n’est « pas satisfait » parce qu’un Vec est une collection, pas un itérateur. Demandez-lui-en un avec .iter() (qui emprunte les éléments) ou .into_iter() (qui les prend) :
fn main() { let scores = vec![70, 85, 92]; let curved: Vec<i32> = scores.iter().map(|s| s + 5).collect(); println!("{:?}", curved);}Sortie :
[75, 90, 97]Solution 4 : ajouter une contrainte de trait au générique T
Section intitulée « Solution 4 : ajouter une contrainte de trait au générique T »Choisissez-la quand l’erreur dit que la méthode est introuvable « for type parameter T » (pour le paramètre de type T). Dans une fonction générique, Rust ne connaît que ce que les contraintes sur T promettent. Un T tout seul ne promet rien, il n’a donc aucune méthode.
error[E0599]: no method named `to_string` found for type parameter `T` in the current scope --> src/main.rs:2:26 |1 | fn describe<T>(item: T) -> String { | - method `to_string` not found for this type parameter2 | format!("[{}]", item.to_string()) | ^^^^^^^^^ method cannot be called on `T` due to unsatisfied trait bounds |help: the following trait defines an item `to_string`, perhaps you need to restrict type parameter `T` with it: |1 | fn describe<T: ToString>(item: T) -> String { | ++++++++++Rustc vous indique le trait qui définit to_string et vous propose de l’ajouter comme contrainte sur T. Ajoutez-la : désormais, seuls les types qui peuvent être convertis en chaîne sont acceptés.
fn describe<T: ToString>(item: T) -> String { format!("[{}]", item.to_string())}
fn main() { println!("{}", describe(42)); println!("{}", describe("prêt"));}Sortie :
[42][prêt]Où vous le verrez souvent
Section intitulée « Où vous le verrez souvent »- Une faute de frappe, ou une méthode d’un autre langage.
tasks.push_back(...)sur unVecdonnehelp: you might have meant to use `push`, ettasks.lenght()donnehelp: there is a method `len` with a similar name. Correction : utilisez le nom que rustc propose. - Appeler un
Type::new()que vous n’avez jamais écrit. Rust ne fournit pas de constructeur gratuit :Account::new("Ana", 100)échoue avecno associated function or constant named `new` found for struct `Account`. Correction : ajoutezimpl Account { fn new(owner: &str, balance: i64) -> Self { ... } }, ou construisez la valeur directement avecAccount { owner: ..., balance: ... }. Voir Les structs. - Appeler une fonction associée avec un point. Si
fn new() -> Selfn’a pas de paramètreself,acc.new()échoue avec « this is an associated function, not a method » (c’est une fonction associée, pas une méthode). Correction : appelez-la sur le type,Account::new().
Erreurs liées
Section intitulée « Erreurs liées »- E0425 : cannot find value in this scope : c’est le nom lui-même qui n’est pas visible, pas une méthode sur un type.
- E0277 : trait bound not satisfied : il manque à un type un trait dont une fonction ou un opérateur a besoin. Apparaît souvent à côté d’E0599 dans du code générique.
- E0308 : mismatched types : vous avez un
Option<T>là où unTétait attendu, ou l’inverse. - E0382 : use of moved value : une suite fréquente quand on passe de
.iter()à.into_iter(). - Toutes les erreurs du compilateur : la liste complète, avec un court résumé de chacune.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. Rustc dit « items from traits can only be used if the trait is in scope ». Que devez-vous faire ?
2. names.first().to_uppercase() échoue avec E0599 pour Option<&&str>. Pourquoi ?
3. Vous appelez scores.filter(...) sur un Vec<i32> et rustc dit « Vec<i32> is not an iterator ». Quelle est la correction ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- E0599 — Rust error codes index (en anglais) : l’explication officielle de cette erreur.
- Traits: Defining Shared Behavior — The Rust Book (en anglais) : comment les traits ajoutent des méthodes aux types, et comment fonctionnent les contraintes de trait.
- Processing a Series of Items with Iterators — The Rust Book (en anglais) :
iter(),into_iter()et les méthodes d’itérateur commemap. Option— bibliothèque standard de Rust (en anglais) : toutes les méthodes pour sortir une valeur d’unOption.- Le prélude Rust — bibliothèque standard de Rust (en anglais) : les traits toujours disponibles, et pourquoi
Writen’en fait pas partie.