Errore Rust E0412: cannot find type in this scope (tipo non trovato)
E0412 significa che hai scritto il nome di un tipo che Rust non vede da quel punto, per esempio nella firma di una funzione come fn print_invoice(inv: &Invoce). È un errore molto comune e facile: un errore di battitura, una riga use mancante, o un generico <T> che hai dimenticato di dichiarare. All’inizio una cosa potrebbe confonderti: da Rust 1.93 il compilatore stampa questo errore come E0425, con lo stesso messaggio, cannot find type. Questa pagina li copre entrambi, e fa parte della guida agli errori del compilatore.
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”Ecco cosa stampano Rust 1.93 e le versioni successive (il compilatore attuale è la 1.97):
error[E0425]: cannot find type `Invoce` in this scope --> src/main.rs:2:24 |1 | struct Invoice { total: u32 } | -------------- similarly named struct `Invoice` defined here2 | fn print_invoice(inv: &Invoce) { // ❌ typo: Invoce | ^^^^^^ |help: a struct with a similar name exists |2 | fn print_invoice(inv: &Invoice) { // ❌ typo: Invoce | +E questo è lo stesso programma su Rust 1.92 o precedenti, la versione con cui sono stati scritti la maggior parte dei post e delle risposte su Stack Overflow:
error[E0412]: cannot find type `Invoce` in this scope --> src/main.rs:2:24 |1 | struct Invoice { total: u32 } | -------------- similarly named struct `Invoice` defined here2 | fn print_invoice(inv: &Invoce) { | ^^^^^^ help: a struct with a similar name exists: `Invoice`In entrambi i casi il compilatore ti dice: «non trovo il tipo Invoce in questo scope», e ti fa notare che esiste una struct con un nome simile, Invoice.
Ecco il programma che li provoca tutti e due:
struct Invoice { total: u32 }fn print_invoice(inv: &Invoce) { // ❌ typo: Invoce println!("{}", inv.total);}
fn main() { print_invoice(&Invoice { total: 120 });}(Il commento dice: errore di battitura, Invoce.)
La pagina ufficiale di E0412 (in inglese) ora comincia con «this error code is no longer emitted by the compiler» (questo codice non viene più emesso dal compilatore). Il problema non è sparito, si è solo spostato in E0425, che copre anche variabili e funzioni mancanti. Tutto quello che segue vale allo stesso modo per entrambi i codici.
Cosa significa
Sezione intitolata “Cosa significa”I ^^^^^^ indicano Invoce nella firma. Per controllare questa funzione, Rust deve sapere cos’è un Invoce: quanto è grande, che campi ha. Ha guardato tutti i tipi visibili dalla riga 2 (le tue struct e i tuoi enum, le tue righe use e il prelude) e non ha trovato niente con quel nome.
La riga help: ti dice in quale situazione ti trovi:
- «a struct with a similar name exists»: un errore di battitura. Il
+mostra la lettera mancante. - «consider importing this struct»: il tipo esiste da un’altra parte, e ti serve una riga
use. - «you might be missing a type parameter»: hai usato un generico
Tsenza dichiarare<T>. - nessun help: il tipo non esiste ancora. Non l’hai scritto, oppure è in un file che Rust non conosce.
È come una ricetta che dice «aggiungi 200 g di Invoce». Il cuoco sa cosa sono farina e zucchero, ma non «Invoce», quindi si ferma prima ancora di cominciare.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Rust controlla la firma di ogni funzione prima che il programma parta. Ogni parametro e ogni tipo di ritorno deve nominare un tipo vero e conosciuto, perché Rust lo usa per decidere quanta memoria serve al valore e quali metodi e campi ha. Un nome che non trova non è un’ipotesi che è disposto a fare.
Solo un piccolo gruppo di nomi di tipo è visibile ovunque senza use: il prelude, con String, Vec, Option, Result, Box e pochi altri. Per tutto il resto serve una tua definizione, una riga use o un percorso completo come std::num::ParseIntError. Vedi Moduli per capire come funzionano i percorsi e use.
Perché è cambiato il codice? Da Rust 1.93, rustc segnala un tipo mancante con E0425, lo stesso codice che usava già per una variabile o una funzione mancante. Il messaggio dice comunque type, quindi capisci sempre che tipo di nome manca.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: correggi il nome, o definisci il tipo
Sezione intitolata “Soluzione 1: correggi il nome, o definisci il tipo”Scegli questa strada quando rustc dice che esiste un nome simile, oppure non dà nessun help. I nomi dei tipi distinguono maiuscole e minuscole: invoice, Invoce e Invoice sono tre nomi diversi. Se non c’è un nome simile, scrivi prima la struct o l’enum:
struct Invoice { total: u32,}
fn print_invoice(inv: &Invoice) { println!("Totale fattura: {} EUR", inv.total);}
fn main() { print_invoice(&Invoice { total: 120 });}Output:
Totale fattura: 120 EURSoluzione 2: aggiungi la riga use che suggerisce rustc
Sezione intitolata “Soluzione 2: aggiungi la riga use che suggerisce rustc”Scegli questa strada quando l’help dice consider importing this struct (o enum, o type alias). I tipi della libreria standard che non sono nel prelude, come HashMap, ParseIntError o Ordering, hanno bisogno di una riga use. Qui una funzione restituisce un errore di conversione:
error[E0425]: cannot find type `ParseIntError` in this scope --> src/main.rs:1:40 |1 | fn parse_age(text: &str) -> Result<u8, ParseIntError> { | ^^^^^^^^^^^^^ not found in this scope |help: consider importing this struct |1 + use std::num::ParseIntError; |Copia la riga suggerita in cima al file:
use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u8, ParseIntError> { text.trim().parse()}
fn main() { println!("{:?}", parse_age(" 42 ")); println!("{:?}", parse_age("quaranta").is_err());}Output:
Ok(42)trueSe hai scritto HashMap::new() (un percorso con ::) invece di un tipo in una firma, l’errore è invece E0433, e lo risolve la stessa riga use. Se rustc suggerisce più import, leggili prima di scegliere; sono tipi diversi che hanno lo stesso nome.
Soluzione 3: dichiara il parametro di tipo generico
Sezione intitolata “Soluzione 3: dichiara il parametro di tipo generico”Scegli questa strada quando l’help dice you might be missing a type parameter. In Rust, T non è una parola speciale. È un nome che inventi tu, e devi annunciarlo tra parentesi angolari dopo il nome della funzione. Senza <T>, Rust cerca un vero tipo chiamato T:
error[E0425]: cannot find type `T` in this scope --> src/main.rs:1:21 |1 | fn largest(items: &[T]) -> &T { | ^ not found in this scope |help: you might be missing a type parameter |1 | fn largest<T>(items: &[T]) -> &T { | +++Ottieni lo stesso errore una volta per ogni punto in cui compare T. Aggiungi <T>, più eventuali trait di cui la funzione ha bisogno. Per confrontare gli elementi con >, T deve implementare PartialOrd:
fn largest<T: PartialOrd>(items: &[T]) -> &T { let mut best = &items[0]; for item in items { if item > best { best = item; } } best}
fn main() { println!("{}", largest(&[34, 50, 25, 100, 65])); println!("{}", largest(&['y', 'm', 'a', 'q']));}Output:
100yLo stesso vale per le struct: struct Wrapper { items: Vec<Item> } fallisce a meno che tu non scriva struct Wrapper<Item> o definisca un vero tipo Item. Se ometti : PartialOrd ottieni invece E0369 sul >. Vedi Generici.
Soluzione 4: importa un tipo da un altro modulo
Sezione intitolata “Soluzione 4: importa un tipo da un altro modulo”Scegli questa strada quando il tipo è tuo ma vive in un altro modulo. Una sorpresa comune: nemmeno un modulo dentro il tuo file vede i tipi in cima al file. Ogni modulo ha il suo scope:
error[E0425]: cannot find type `Order` in this scope --> src/main.rs:7:26 |7 | pub fn print(order: &Order) -> String { | ^^^^^ not found in this scope |help: consider importing this struct |7 + use crate::Order; |Il 7 + vuol dire «aggiungi questa riga dentro il modulo, alla riga 7». crate::Order è il percorso dalla radice del tuo crate; funziona anche super::Order («dal modulo genitore»):
struct Order { id: u32, total: u32,}
mod receipts { use crate::Order;
pub fn print(order: &Order) -> String { format!("Ordine n. {}: {} EUR", order.id, order.total) }}
fn main() { let order = Order { id: 7, total: 42 }; println!("{}", receipts::print(&order));}Output:
Ordine n. 7: 42 EURNella direzione opposta funziona allo stesso modo: un tipo definito in mod shop ha bisogno di pub struct Product e di use crate::shop::Product; (o del percorso completo shop::Product) prima che main possa nominarlo. Lo incontrerai soprattutto in mod tests, dove use super::*; in cima importa tutto dal genitore.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Un tipo da un file che non hai dichiarato. fn save(user: models::User) con un file src/models.rs ma senza la riga mod models; non è E0412 né E0425, ma E0433: cannot find module or crate `models` in this scope. Soluzione: aggiungi mod models; in cima a main.rs, e rendi pub la struct.
Self fuori da un impl. fn new_counter() -> Self al livello più esterno ha un suo codice, E0411: cannot find type `Self` in this scope, con l’etichetta `Self` is only available in impls, traits, and type definitions. Soluzione: sposta la funzione in impl Counter { ... }, oppure scrivi Counter invece di Self.
Un trait invece di un tipo. impl Display for Point senza importare Display dà E0405, cannot find trait `Display` in this scope, con help: consider importing this trait, use std::fmt::Display;. Stessa idea, stessa soluzione: aggiungi la riga use. Vedi Trait.
Errori correlati
Sezione intitolata “Errori correlati”- E0425: non trova un valore, una funzione, e da Rust 1.93 anche un tipo. Il codice che vedrai davvero oggi.
- E0433: non trova la prima parte di un percorso come
HashMap::new()omodels::User. - E0432: import non risolto, quando la riga
usestessa non punta a niente. - E0603: il tipo è stato trovato, ma non è
pub. - E0405 (trait non trovato) ed E0411 (
Selffuori da un impl): i parenti stretti visti sopra. - Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Hai seguito un tutorial che mostra error[E0412]: cannot find type, ma il tuo compilatore stampa error[E0425]: cannot find type. Perché?
2. fn first(items: &[T]) -> &T dà cannot find type T. Qual è la soluzione?
3. Una funzione dentro mod billing usa Order, una struct definita in cima a main.rs. Quale riga, dentro il modulo, lo risolve?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0412 — Rust error codes index (in inglese): la pagina ufficiale, con la nota che questo codice non viene più emesso, e gli esempi classici.
- E0425 — Rust error codes index (in inglese): il codice che usa oggi il compilatore per questo errore.
- Generic Data Types — The Rust Book (in inglese): come dichiarare
<T>, con la stessa funzionelargestdella Soluzione 3. - Bringing Paths into Scope with the
useKeyword — The Rust Book (in inglese):use,crate::esuper::per i tipi di altri moduli. std::prelude— documentazione della libreria standard (in inglese): l’elenco dei nomi che puoi usare senza importarli.