Aller au contenu

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.

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 scope
help: 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();
}

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.

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.

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
▶ Essayez par vous-même

(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é : ANA
Dernier invité : Some("CHEN")
▶ Essayez par vous-même

.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.

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]
▶ Essayez par vous-même

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 parameter
2 | 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]
▶ Essayez par vous-même
  • Une faute de frappe, ou une méthode d’un autre langage. tasks.push_back(...) sur un Vec donne help: you might have meant to use `push`, et tasks.lenght() donne help: 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 avec no associated function or constant named `new` found for struct `Account`. Correction : ajoutez impl Account { fn new(owner: &str, balance: i64) -> Self { ... } }, ou construisez la valeur directement avec Account { owner: ..., balance: ... }. Voir Les structs.
  • Appeler une fonction associée avec un point. Si fn new() -> Self n’a pas de paramètre self, 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().

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