Errore Rust E0599: no method named X found (metodo non trovato)
L’errore E0599 significa che hai chiamato un metodo che Rust non trova su quel tipo. È molto comune, e la causa di solito è una di poche: un trait che non hai importato, un Option che non hai aperto, un Vec trattato come se fosse un iteratore, oppure un semplice errore di battitura. La buona notizia è che le righe help: di rustc spesso ti dicono la soluzione esatta. Questa pagina fa parte della guida agli errori del compilatore.
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”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; |Il compilatore dice: «nessun metodo write_all trovato per la struct Stdout in questo scope», e suggerisce di importare il trait Write. Questo è il programma che l’ha prodotto:
use std::io;
fn main() { let mut out = io::stdout(); out.write_all(b"Server started\n").unwrap();}Cosa significa
Sezione intitolata “Cosa significa”I ^^^^ indicano il nome del metodo, write_all, e la prima riga ti dice su quale tipo Rust l’ha cercato: Stdout. Quindi il messaggio si legge così: «Ho guardato in Stdout e non ho trovato nessun metodo write_all che io possa usare qui».
Il tipo nella prima riga è l’indizio più utile di tutto il messaggio. Se dice Option<T>, Result<T, E>, Vec<_> o un parametro di tipo T quando ti aspettavi altro, sai già quale delle soluzioni qui sotto ti serve.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”In Rust molti metodi non appartengono al tipo stesso. Arrivano da un trait. write_all viene dal trait Write, e Stdout lo implementa. Ma i metodi di un trait funzionano solo in un file che ha quel trait nello scope (ambito), di solito grazie a una riga use. Ecco cosa vuol dire «items from traits can only be used if the trait is in scope» (gli elementi dei trait si possono usare solo se il trait è nello scope).
Questa regola rende il codice prevedibile. Due crate diversi possono aggiungere entrambi un metodo write_all allo stesso tipo, tramite trait diversi. Se tutti i trait fossero sempre attivi, non potresti capire quale dei due intende una chiamata. Con la regola contano solo i trait che hai importato.
Le altre cause nascono dai tipi rigorosi di Rust. Un Option<&str> non è un &str, quindi non ha i metodi di &str. Un generico T potrebbe essere qualsiasi tipo, quindi Rust ti lascia chiamare solo i metodi promessi dai vincoli su T.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: Importa il trait
Sezione intitolata “Soluzione 1: Importa il trait”Scegli questa quando l’help dice «items from traits can only be used if the trait is in scope». Aggiungi la riga use suggerita da rustc.
use std::io::{self, Write};
fn main() { let mut out = io::stdout(); out.write_all(b"Server avviato\n").unwrap();}Output:
Server avviatoLo stesso succede con il crate rand. Senza l’import, rng.random_range(1..=6) non compila, e rustc ti dice quale trait portare nello scope:
help: trait `RngExt` which provides `random_range` is implemented but not in scope; perhaps you want to import it |1 + use rand::RngExt;Attenzione: in rand 0.10 il trait si chiama RngExt. I tutorial più vecchi dicono use rand::Rng, e con rand 0.10 quell’import ti dà proprio questo stesso errore. Segui la riga help:, non il tutorial.
Soluzione 2: Estrai prima il valore dall’Option o dal Result
Sezione intitolata “Soluzione 2: Estrai prima il valore dall’Option o dal Result”Scegli questa quando il tipo nell’errore è Option<T> o Result<T, E>. Il valore che ti serve sta dentro, e devi tirarlo fuori prima di chiamare i suoi metodi.
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>`first() restituisce un Option, perché la lista potrebbe essere vuota. rustc suggerisce .expect(...), che funziona ma va in panic con None. Di solito è meglio gestire entrambi i casi:
fn main() { let guests = vec!["ana", "bo", "chen"];
match guests.first() { Some(name) => println!("Primo ospite: {}", name.to_uppercase()), None => println!("Ancora nessun ospite"), }
let shout = guests.last().map(|name| name.to_uppercase()); println!("Ultimo ospite: {:?}", shout);}Output:
Primo ospite: ANAUltimo ospite: Some("CHEN").map() esegue il tuo codice sul valore interno e lascia l’involucro Option. Per un Result (per esempio quello di .parse()), usa match, .unwrap_or(...) oppure ? dentro una funzione che restituisce Result. Vedi Option e Result.
Soluzione 3: Chiama .iter() sul Vec
Sezione intitolata “Soluzione 3: Chiama .iter() sul Vec”Scegli questa quando chiami .map(), .filter() o un altro metodo degli iteratori direttamente su un Vec. Qui l’errore ha un aspetto diverso:
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`Per alcuni metodi, come filter, il messaggio è più gentile: rustc dice che il Vec<i32> «is not an iterator» (non è un iteratore) e aggiunge help: call `.into_iter()` first. Stessa causa, stessa soluzione.
Vec<{integer}>: Iterator è «not satisfied» (non soddisfatto) perché un Vec è una collezione, non un iteratore. Chiedigliene uno con .iter() (prende in prestito gli elementi) o .into_iter() (li prende per sé):
fn main() { let scores = vec![70, 85, 92]; let curved: Vec<i32> = scores.iter().map(|s| s + 5).collect(); println!("{:?}", curved);}Output:
[75, 90, 97]Soluzione 4: Aggiungi un vincolo di trait al generico T
Sezione intitolata “Soluzione 4: Aggiungi un vincolo di trait al generico T”Scegli questa quando l’errore dice che il metodo non è stato trovato «for type parameter T» (per il parametro di tipo T). Dentro una funzione generica, Rust sa solo quello che promettono i vincoli su T. Un T senza vincoli non promette niente, quindi non ha metodi.
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 { | ++++++++++Aggiungi il vincolo che suggerisce rustc. Ora vengono accettati solo i tipi che si possono trasformare in stringa:
fn describe<T: ToString>(item: T) -> String { format!("[{}]", item.to_string())}
fn main() { println!("{}", describe(42)); println!("{}", describe("pronto"));}Output:
[42][pronto]Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”- Un errore di battitura o un metodo preso da un altro linguaggio.
tasks.push_back(...)su unVecdàhelp: you might have meant to use `push`, etasks.lenght()dàhelp: there is a method `len` with a similar name. Soluzione: usa il nome suggerito da rustc. - Chiamare un
Type::new()che non hai mai scritto. Rust non regala costruttori:Account::new("Ana", 100)fallisce conno associated function or constant named `new` found for struct `Account`. Soluzione: aggiungiimpl Account { fn new(owner: &str, balance: i64) -> Self { ... } }, oppure costruiscilo direttamente conAccount { owner: ..., balance: ... }. Vedi Struct. - Chiamare una funzione associata con il punto. Se
fn new() -> Selfnon ha il parametroself,acc.new()fallisce con «this is an associated function, not a method» (è una funzione associata, non un metodo). Soluzione: chiamala sul tipo,Account::new().
Errori correlati
Sezione intitolata “Errori correlati”- E0425: cannot find value in this scope: non è visibile il nome stesso, non un metodo su un tipo.
- E0277: trait bound not satisfied: a un tipo manca un trait richiesto da una funzione o da un operatore. Compare spesso accanto a E0599 nel codice generico.
- E0308: mismatched types: hai un
Option<T>dove serviva unT, o il contrario. - E0382: use of moved value: un errore che arriva spesso dopo essere passati da
.iter()a.into_iter(). - Tutti gli errori del compilatore: l’elenco completo, con un breve riassunto di ciascuno.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. rustc dice "items from traits can only be used if the trait is in scope". Cosa devi fare?
2. names.first().to_uppercase() fallisce con E0599 per Option<&&str>. Perché?
3. Chiami scores.filter(...) su un Vec<i32> e rustc dice "Vec<i32> is not an iterator". Come lo risolvi?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0599 — Rust error codes index (in inglese): la spiegazione ufficiale di questo errore.
- Traits: Defining Shared Behavior — The Rust Book (in inglese): come i trait aggiungono metodi ai tipi e come funzionano i vincoli di trait.
- Processing a Series of Items with Iterators — The Rust Book (in inglese):
iter(),into_iter()e i metodi degli iteratori comemap. Option— Rust standard library (in inglese): tutti i metodi per tirare fuori un valore da unOption.- The Rust prelude — Rust standard library (in inglese): i trait che sono sempre nello scope, e perché
Writenon è tra questi.