Salta ai contenuti

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.

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);
}

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.

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.

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)
▶ Provalo tu

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 caratteri
▶ Provalo tu

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

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:

9
▶ Provalo tu

Se non c’è nessun nome simile e nessun suggerimento di import, il trait non esiste ancora. Prima definiscilo con trait Shape { ... }. Vedi Trait in Rust.

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:

4
▶ Provalo tu

Lo stesso vale per i trait dei crate: impl Serialize for User ha bisogno prima di use serde::Serialize;. Vedi Moduli in Rust.

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.

  • 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::Display senza use 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

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