Errori del compilatore Rust spiegati
Il compilatore Rust ti ha mostrato un errore rosso e non sai bene che cosa vuole? Sei nel posto giusto. Ogni sviluppatore Rust vede questi errori, spesso molte volte al giorno. La buona notizia: quelli che incontrerai di continuo sono solo una manciata, e una volta che li conosci smettono di fare paura.
Ogni pagina qui sotto prende un codice di errore, mostra il messaggio reale, lo spiega in parole semplici e ti dà soluzioni che puoi eseguire nel browser. Il compilatore scrive i messaggi in inglese, quindi nella tabella li trovi così come appaiono nel terminale.
Gli errori più comuni
Sezione intitolata “Gli errori più comuni”| Errore | Che cosa dice il compilatore | In parole semplici |
|---|---|---|
| E0382 | borrow of moved value | Hai ceduto un valore e poi hai provato a usarlo di nuovo |
| E0502 | cannot borrow as mutable because it is also borrowed as immutable | Stai modificando qualcosa mentre qualcuno lo sta ancora leggendo |
| E0499 | cannot borrow as mutable more than once at a time | Due punti del codice vogliono modificare la stessa cosa nello stesso momento |
| E0308 | mismatched types | Hai dato un tipo dove ne era atteso un altro |
| E0277 | the trait bound is not satisfied | Un tipo non sa fare una cosa che gli hai chiesto (stampare, confrontare, sommare…) |
| E0106 | missing lifetime specifier | Rust non riesce a capire per quanto tempo resta valido un riferimento restituito |
| E0425 | cannot find value in this scope | Un nome è scritto male, o è usato fuori dal blocco in cui vive |
| E0599 | no method named … found | Il metodo non esiste su quel tipo, oppure il suo trait non è importato |
| E0384 | cannot assign twice to immutable variable | Hai cambiato una variabile che non era dichiarata mut |
| E0596 | cannot borrow as mutable, as it is not declared as mutable | Hai provato a modificare qualcosa tramite una variabile o un riferimento che non è mut |
| E0597 | borrowed value does not live long enough | Un riferimento è ancora in uso dopo che il valore a cui punta è sparito |
| E0515 | cannot return reference to local variable | Hai restituito un riferimento a qualcosa che viene distrutto alla fine della funzione |
| E0373 | closure may outlive the current function, but it borrows … | Una closure (spesso un thread) prende in prestito una variabile locale che potrebbe sparire prima che la closure giri |
| E0369 | binary operation == cannot be applied to type … |
Il tuo tipo non supporta (ancora) ==, <, + e simili |
| E0432 | unresolved import | Una riga use punta a un crate, un modulo o un elemento che non si trova |
| E0433 | cannot find type … in this scope (older: failed to resolve) | Un percorso come HashMap::new() usa un nome non importato o inesistente |
| E0424 | self value is a keyword only available in methods with a self parameter |
Hai usato self in una funzione che non riceve self |
| E0061 | this function takes N arguments but M arguments were supplied | Hai passato troppi o troppo pochi argomenti (Rust non ha argomenti opzionali) |
| E0594 | cannot assign to p.hp, as p is not declared as mutable |
Hai cambiato un campo o un valore dietro un & senza accesso mut |
| E0004 | non-exhaustive patterns: X not covered |
Il tuo match non gestisce tutti i valori possibili |
| E0507 | cannot move out of x which is behind a shared reference |
Hai provato a prendere l’ownership di qualcosa che hai solo in prestito |
| E0603 | function x is private |
Hai usato una funzione, una struct o un modulo che non è pub |
| E0716 | temporary value dropped while borrowed | Hai tenuto un riferimento a un valore che viene buttato via alla fine della riga |
| E0463 | can’t find crate for x |
Un crate (o la libreria standard per un target) non è installato |
| E0368 | binary assignment operation += cannot be applied to type … |
Il tuo tipo non supporta +=, -= e simili |
| E0057 | this function takes N arguments but M were supplied (note: closure defined here) | Hai chiamato una closure con troppi o troppo pochi argomenti |
| E0282 | type annotations needed | Rust non riesce a dedurre un tipo da solo, quindi devi scriverlo tu |
| E0609 | no field x on type T |
Il nome del campo è sbagliato, oppure il valore è avvolto in qualcos’altro (per esempio in un Option) |
| E0593 | closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments | Una closure riceve argomenti separati dove è attesa una tupla (o un numero diverso di argomenti) |
| E0631 | type mismatch in closure arguments | Il tipo di un parametro della closure non corrisponde a quello che riceve (spesso i32 invece di &i32) |
| E0005 | refutable pattern in local binding | let Some(x) = … può fallire, quindi un semplice let non lo accetta |
| E0615 | attempted to take value of method len on type String |
Hai scritto s.len invece di s.len() |
| E0610 | {integer} is a primitive type and therefore doesn’t have fields |
Hai usato .campo su un numero, un bool o un char |
| E0560 | struct User has no field named nmae |
Un letterale di struct usa un campo che la struct non ha |
| E0616 | field balance of struct Account is private |
Hai letto un campo non pub da fuori del suo modulo |
| E0451 | field x of struct Y is private |
Hai creato una struct con un letterale mentre alcuni suoi campi sono privati |
| E0624 | method x is private |
Hai chiamato un metodo o una funzione associata che non è pub |
| E0283 | type annotations needed (cannot infer type … multiple impls satisfy this bound) | Più tipi potrebbero andare bene (per esempio con .collect() o .sum()), quindi devi sceglierne uno |
| E0284 | type annotations needed: cannot satisfy <_ as FromStr>::Err == _ |
"42".parse() non sa in quale tipo convertire |
| E0790 | cannot call associated function on trait without specifying the corresponding impl type |
Hai scritto Default::default() o Trait::new() senza dire quale tipo |
| E0559 | variant Shape::Circle has no field named r |
Il letterale di una variante di enum usa un campo che la variante non ha |
| E0063 | missing field email in initializer of User |
Hai creato una struct dimenticando uno o più campi |
| E0689 | can’t call method pow on ambiguous numeric type {integer} |
2.pow(10) o 2.0.sqrt() hanno bisogno di un tipo numerico preciso, come i32 o f64 |
| E0034 | multiple applicable items in scope | Due trait danno al tuo tipo un metodo con lo stesso nome, quindi Rust non sa quale scegliere |
| E0412 | cannot find type X in this scope (Rust 1.93+ prints E0425) |
Il nome di un tipo è scritto male, non è importato o non è dichiarato |
| E0428 | the name area is defined multiple times |
Due elementi hanno lo stesso nome; Rust non ha l’overloading delle funzioni |
| E0026 | variant Shape::Circle does not have a field named r |
Un pattern nomina un campo che la struct o la variante non ha |
| E0027 | pattern does not mention fields id, paid |
Un pattern di struct tralascia dei campi; aggiungili o termina con .. |
| E0533 | expected unit struct, unit variant or constant, found struct variant Shape::Circle |
Una variante con campi (o una funzione) è usata dove serve un nome semplice; aggiungi { .. } |
| E0592 | duplicate definitions with name reset |
Due blocchi impl definiscono un metodo con lo stesso nome |
| E0255 | the name Error is defined multiple times |
Un use importa un nome uguale a quello di un tuo tipo o di una tua funzione |
| E0252 | the name Result is defined multiple times |
Due righe use importano lo stesso nome; rinominane una con as |
| E0411 | cannot find type Self in this scope |
Hai usato Self fuori da un impl o da un trait |
| E0405 | cannot find trait Display in this scope |
Il nome di un trait è scritto male o non è importato (per esempio use std::fmt::Display;) |
| E0532 | expected unit struct, unit variant or constant, found tuple variant Shape::Circle |
Un pattern nomina una variante tupla (o una struct) senza le sue ( ), o aggiunge ( ) dove non servono |
| E0164 | expected tuple struct or tuple variant, found struct variant Shape::Circle |
Un pattern usa ( ) su una variante con campi o su un elemento associato; usa { } o una guardia |
| E0404 | expected trait, found derive macro Debug |
Hai scritto impl X for o T: X dove X è una struct, un alias o una derive macro non importata |
| E0401 | can’t use generic parameters from outer item | Una fn interna usa il T o il Self della funzione esterna; dalle generici suoi o usa una closure |
| E0107 | enum takes 2 generic arguments but 1 generic argument was supplied | Result<u32>, HashMap<String> e simili: troppi o troppo pochi argomenti tra < > |
| E0530 | match bindings cannot shadow tuple variants | Il nome nudo di una variante come Circle => (dopo use Shape::*) non può diventare una nuova variabile |
| E0434 | can’t capture dynamic environment in a fn item | Una fn interna non vede le variabili locali esterne; usa una closure o passagliele |
| E0601 | main function not found in crate main |
L’eseguibile non ha una fn main() (manca, è scritta male, sta dentro un mod, o in realtà è una libreria) |
| E0658 | use of unstable library feature iter_intersperse |
Hai usato un’API solo nightly su Rust stabile; usa l’alternativa stabile o aggiorna |
| E0614 | type u32 cannot be dereferenced |
Hai scritto *x dove x è già un valore semplice, non un riferimento |
| E0435 | attempt to use a non-constant value in a constant | Una const, la lunghezza di un array o una static usa una variabile let; rendila una const o usa un Vec |
| E0554 | #![feature] may not be used on the stable release channel |
Hai copiato codice solo nightly; togli l’attributo e usa l’API stabile, oppure usa nightly di proposito |
Come leggere un errore di Rust
Sezione intitolata “Come leggere un errore di Rust”I messaggi di errore di Rust sono famosi per essere utili, ma contengono parecchie informazioni. Eccone uno reale:
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(); | ++++++++Leggilo in questo ordine:
- La prima riga è il riassunto: il codice di errore (
E0382) e una descrizione di una riga. Qui: «prestito di un valore spostato». - La riga con la freccia (
--> src/main.rs:4:16) ti dice il file, la riga e la colonna dove le cose sono andate storte. - I segni
^^^^indicano il punto esatto dell’errore. I segni----raccontano la storia che ha portato fin lì. Qui dicono: il valore è stato creato alla riga 2, spostato alla riga 3 e poi usato alla riga 4. help:è la soluzione suggerita dal compilatore, spesso con il codice esatto da aggiungere (i segni++++mostrano i caratteri nuovi). Non è sempre la soluzione migliore, ma è un ottimo punto di partenza.
Comincia a leggere dal primo errore. Un solo sbaglio può provocare una catena di errori successivi, e correggere il primo spesso fa sparire anche gli altri.
Tre abitudini che aiutano
Sezione intitolata “Tre abitudini che aiutano”-
Chiedi di più al compilatore. Ogni codice di errore ha una spiegazione più lunga già integrata. Esegui questo in un terminale:
Terminal window rustc --explain E0382Otterrai una breve descrizione (in inglese), un esempio sbagliato e uno corretto.
-
Controlla spesso.
cargo checktrova gli errori senza compilare l’intero programma, quindi è molto più veloce dicargo build. Se lo esegui ogni poche righe, incontri un errore alla volta, non venti. Vedi Cargo e crate. -
Fai mostrare gli errori all’editor mentre scrivi. Con l’estensione rust-analyzer gli errori compaiono direttamente nel codice, con lo stesso testo di aiuto. Vedi Strumenti e configurazione.
Perché Rust ha così tanti errori
Sezione intitolata “Perché Rust ha così tanti errori”La maggior parte di questi errori esiste perché Rust controlla, prima che il programma parta, cose che altri linguaggi scoprono solo durante l’esecuzione (o mai): usare memoria già liberata, due thread che modificano gli stessi dati, un controllo sul null dimenticato. Ogni errore che correggi è un bug che non arriverà mai ai tuoi utenti.
Per questo molti dicono: in Rust la battaglia si combatte durante la compilazione, e poi il programma semplicemente funziona. Le regole dietro gli errori più comuni sono spiegate in Ownership, Prestito (borrowing) e Lifetime.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Un errore di Rust mostra diversi problemi. Quale dovresti correggere per primo?
2. Che cosa fa rustc --explain E0382?
3. In un messaggio di errore, che cosa indicano i segni ^^^^?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- Rust Compiler Error Index (in inglese): l’elenco ufficiale di tutti i codici di errore, ognuno con un esempio sbagliato e uno corretto.
- Understanding Ownership — The Rust Book (in inglese): le regole dietro gli errori più comuni di prestito e spostamento.
- Error Handling — The Rust Book (in inglese): come Rust gestisce gli errori nei tuoi programmi (
Resultepanic!), non solo gli errori del compilatore. - What is rustc? — The rustc Book (in inglese): come funziona il compilatore, comprese le sue opzioni e i livelli dei lint.