Errore Rust E0405: cannot find trait in this scope (trait non trovato)
E0405 significa che hai nominato un trait che Rust non vede da quel punto. Il caso classico: scrivi impl Display for Point per rendere stampabile la tua struct, ma non hai mai importato Display. Un errore di battitura nel nome del trait, o un trait che vive in un altro modulo, danno lo stesso errore. È uno degli errori più facili da correggere, perché di solito rustc stampa esattamente la riga use che ti serve. A differenza di E0412 («cannot find type»), che in Rust 1.93 è diventato E0425, questo codice non è cambiato: rustc 1.97 stampa ancora E0405 per i trait. Fa parte della guida agli errori del compilatore.
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”error[E0405]: cannot find trait `Display` in this scope --> src/main.rs:6:6 |6 | impl Display for Point { // ❌ `Display` was never imported | ^^^^^^^ not found in this scope |help: consider importing this trait |1 + use std::fmt::Display; |Il compilatore dice: non trova il trait Display in questo scope, e ti suggerisce di importarlo. Questo è il programma che produce l’errore:
struct Point { x: i32, y: i32,}
impl Display for Point { // ❌ `Display` was never imported fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "({}, {})", self.x, self.y) }}
fn main() { let p = Point { x: 3, y: 4 }; println!("{}", p);}Cosa significa
Sezione intitolata “Cosa significa”Il ^^^^^^^ indica Display alla riga 6, con l’etichetta «not found in this scope» (non trovato in questo scope). Rust ha guardato ogni trait visibile da lì: quelli definiti in questo modulo, quelli che portano le tue righe use e il piccolo insieme del prelude. Nessuno si chiama Display.
L’help: ti dice dove si trova: use std::fmt::Display;. L’1 + significa «aggiungi questa come nuova riga 1», in cima al file.
Perché manca Display, se println! lo usa di continuo? Il prelude, la lista di nomi che ogni file Rust riceve gratis, comprende Clone, Iterator, From, Default e altri trait di tutti i giorni, ma non Display, Error, Hash o Write. Quelli vivono nei loro moduli (std::fmt, std::error, std::hash, std::io), e li importi quando li implementi.
È come una ricetta che dice «usa la padella Display». Il cuoco conosce le padelle sul fornello, ma questa sta in un mobile, e la ricetta non ha mai detto in quale.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Rust non cerca mai un nome in tutta la libreria standard, né in tutto il tuo progetto. Guarda solo ciò che è in scope: i tuoi item, le tue righe use e il prelude. Così i nomi restano prevedibili. Solo in std ci sono diversi trait chiamati Write ed Error, e un crate che aggiungi in futuro potrebbe portarne altri. Se Rust ne scegliesse uno per te, aggiungere una dipendenza potrebbe cambiare in silenzio il significato del tuo codice.
Quindi dici quale trait intendi, una volta, in cima al file. La riga di help fa la ricerca al posto tuo e ti suggerisce il trait che ha trovato. Vedi Moduli in Rust per capire come funziona use, e Trait comuni in Rust per Display.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: aggiungi la riga use che suggerisce rustc
Sezione intitolata “Soluzione 1: aggiungi la riga use che suggerisce rustc”Scegli questa quando l’help dice consider importing this trait, cioè quasi sempre. Copia la riga in cima al file:
use std::fmt::Display;
struct Point { x: i32, y: i32,}
impl Display for Point { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "({}, {})", self.x, self.y) }}
fn main() { let p = Point { x: 3, y: 4 }; println!("{}", p); println!("Ferris si trova in {}", Point { x: -1, y: 7 });}Output:
(3, 4)Ferris si trova in (-1, 7)Se rustc suggerisce più import, leggili prima di scegliere. Sono trait diversi che hanno per caso lo stesso nome, come std::fmt::Write e std::io::Write.
Soluzione 2: importa il modulo e scrivi fmt::Display
Sezione intitolata “Soluzione 2: importa il modulo e scrivi fmt::Display”Scegli questa quando implementi Display, perché tanto ti servono anche Formatter e Result dallo stesso modulo. Importa std::fmt una volta e scrivi fmt:: davanti a tutti e tre. È lo stile che vedrai più spesso nel codice Rust vero:
use std::fmt;
struct Point { x: i32, y: i32,}
impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) }}
fn main() { let p = Point { x: 3, y: 4 }; let label = p.to_string(); println!("{} ha {} caratteri", label, label.len());}Output:
(3, 4) ha 6 caratteriImplementare Display ti regala anche .to_string(). Puoi saltare del tutto lo use e scrivere impl std::fmt::Display for Point; per un caso isolato va benissimo.
Soluzione 3: correggi il nome del trait
Sezione intitolata “Soluzione 3: correggi il nome del trait”Scegli questa quando rustc dice a trait with a similar name exists (esiste un trait con un nome simile). I nomi dei trait distinguono maiuscole e minuscole, quindi shape, Shap e Shape sono tre nomi diversi:
error[E0405]: cannot find trait `Shap` in this scope --> src/main.rs:9:6 |1 | trait Shape { | ----------- similarly named trait `Shape` defined here...9 | impl Shap for Square { // ❌ typo: Shap | ^^^^ |help: a trait with a similar name exists |9 | impl Shape for Square { // ❌ typo: Shap | +Il programma che non compila:
trait Shape { fn area(&self) -> f64;}
struct Square { side: f64,}
impl Shap for Square { // ❌ typo: Shap fn area(&self) -> f64 { self.side * self.side }}
fn main() { let s = Square { side: 3.0 }; println!("{}", s.area());}Il + sotto la riga 9 mostra la lettera che manca. Aggiungila:
trait Shape { fn area(&self) -> f64;}
struct Square { side: f64,}
impl Shape for Square { fn area(&self) -> f64 { self.side * self.side }}
fn main() { let s = Square { side: 3.0 }; println!("{}", s.area());}Output:
9Se non c’è nessun nome simile e nessun suggerimento di import, il trait non esiste ancora. Prima definiscilo con trait Shape { ... }. Vedi Trait in Rust.
Soluzione 4: importa il tuo trait dal suo modulo
Sezione intitolata “Soluzione 4: importa il tuo trait dal suo modulo”Scegli questa quando il trait è tuo ma vive in un altro modulo. Ogni modulo ha il suo scope, quindi un trait in mod shapes non è visibile in cima a main.rs finché non lo importi:
error[E0405]: cannot find trait `Shape` in this scope --> src/main.rs:11:6 |11 | impl Shape for Square { // ❌ `Shape` lives in `mod shapes` | ^^^^^ not found in this scope |help: consider importing this trait | 1 + use crate::shapes::Shape; |Il programma che non compila:
mod shapes { pub trait Shape { fn area(&self) -> f64; }}
struct Square { side: f64,}
impl Shape for Square { // ❌ `Shape` lives in `mod shapes` fn area(&self) -> f64 { self.side * self.side }}
fn main() { println!("{}", Square { side: 2.0 }.area());}Aggiungi la riga use, e controlla che il trait sia pub. Senza pub, è l’import stesso a fallire con E0603, «trait is private» (il trait è privato):
mod shapes { pub trait Shape { fn area(&self) -> f64; }}
use crate::shapes::Shape;
struct Square { side: f64,}
impl Shape for Square { fn area(&self) -> f64 { self.side * self.side }}
fn main() { println!("{}", Square { side: 2.0 }.area());}Output:
4Lo stesso vale per i trait dei crate: impl Serialize for User ha bisogno prima di use serde::Serialize;. Vedi Moduli in Rust.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Box<dyn Error> in main o in un helper. fn run() -> Result<(), Box<dyn Error>> senza import dà cannot find trait `Error` in this scope, con help: consider importing this trait e use std::error::Error;. Correzione: aggiungi quella riga, oppure scrivi Box<dyn std::error::Error>. Vedi Errori personalizzati in Rust.
Vincoli di trait sui generici. fn print_all<T: Display>(items: &[T]) dà lo stesso E0405 per Display, indicando il vincolo. Correzione: use std::fmt::Display;. Vedi Generici in Rust.
Debug dà un codice diverso. impl Debug for Point o T: Debug senza import non è E0405 ma E0404: expected trait, found derive macro `Debug` . Il prelude contiene la macro #[derive(Debug)], ma non il trait Debug. Correzione: use std::fmt::Debug; (lo suggerisce rustc), oppure semplicemente #[derive(Debug)] se non ti serve un formato personalizzato.
Errori correlati
Sezione intitolata “Errori correlati”- E0425: non trova un valore, una funzione o (da Rust 1.93) un tipo in questo scope.
- E0412: il vecchio codice per «cannot find type», ora segnalato come E0425.
- E0433: non trova la prima parte di un percorso, come
fmt::Displaysenzause std::fmt;. - E0599: metodo non trovato, spesso perché il trait che fornisce il metodo non è importato.
- E0277: il trait è stato trovato, ma il tuo tipo non lo implementa.
- E0404: un nome che esiste, ma non è un trait (come la macro
Debug), vedi sopra. - Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Scrivi impl Display for Invoice e ottieni E0405. Che cosa manca?
2. Quale di questi trait puoi usare senza nessuna riga use?
3. Il tuo trait Shape è definito in mod shapes, e impl Shape for Square sta in main.rs. Che cosa ti serve?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0405 — Rust error codes index (in inglese): la spiegazione ufficiale, con le due correzioni: importare il trait o definirlo.
- Implementing a Trait on a Type — The Rust Book (in inglese): come funziona
impl Trait for Type, e perché il trait deve essere in scope. std::fmt::Display— documentazione della libreria standard (in inglese): il trait di questa pagina, con un esempio completo diimpl fmt::Display.- Display — Rust by Example (in inglese): implementare
Displaypasso per passo, conuse std::fmt;. std::prelude— documentazione della libreria standard (in inglese): la lista di trait e tipi che puoi usare senza importarli.