Zum Inhalt springen

Rust-Fehler E0405: cannot find trait in this scope (Trait nicht gefunden)

E0405 bedeutet: Du hast einen Trait genannt, den Rust an dieser Stelle nicht sehen kann. Der klassische Fall: Du schreibst impl Display for Point, damit sich dein Struct ausgeben lässt, hast Display aber nie importiert. Ein Tippfehler im Namen des Traits oder ein Trait, der in einem anderen Modul liegt, ergibt denselben Fehler. Er gehört zu den am leichtesten zu behebenden Fehlern, weil rustc meistens genau die use-Zeile ausgibt, die du brauchst. Anders als E0412 („cannot find type“), der seit Rust 1.93 als E0425 gemeldet wird, hat sich dieser Code nicht geändert: Auch rustc 1.97 gibt für Traits E0405 aus. Die Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.

error[E0405]: cannot find trait `Display` in this scope
--> src/main.rs:6:6
|
6 | impl Display for Point { // ❌ `Display` wurde nie importiert
| ^^^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use std::fmt::Display;
|

Auf Deutsch: „Der Trait Display wurde in diesem Gültigkeitsbereich nicht gefunden.“ Das help sagt: „Importiere am besten diesen Trait.“

Dieses Programm erzeugt den Fehler:

struct Point {
x: i32,
y: i32,
}
impl Display for Point { // ❌ `Display` wurde nie importiert
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);
}

Die ^^^^^^^ zeigen in Zeile 6 auf Display, mit dem Hinweis „not found in this scope“ (in diesem Gültigkeitsbereich nicht gefunden). Rust hat sich jeden Trait angesehen, der von dort aus sichtbar ist: die, die du in diesem Modul definiert hast, die, die deine use-Zeilen hereinholen, und die kleine Auswahl im Prelude. Keiner davon heißt Display.

Das help: sagt dir, wo er liegt: use std::fmt::Display;. Das 1 + bedeutet „füge das als neue Zeile 1 ein“, also ganz oben in der Datei.

Warum fehlt Display, wo println! es doch ständig benutzt? Das Prelude, die Liste von Namen, die jede Rust-Datei gratis bekommt, enthält Clone, Iterator, From, Default und andere alltägliche Traits, aber nicht Display, Error, Hash oder Write. Die liegen in ihren Modulen (std::fmt, std::error, std::hash, std::io), und du importierst sie, wenn du sie implementierst.

Das ist wie ein Rezept, in dem steht: „Nimm die Display-Pfanne.“ Der Koch kennt die Pfannen auf dem Herd, aber diese steht in einem Schrank, und das Rezept hat nie gesagt, in welchem.

Rust durchsucht nie die ganze Standardbibliothek oder dein ganzes Projekt nach einem Namen. Es schaut nur auf das, was im Gültigkeitsbereich ist: deine eigenen Elemente, deine use-Zeilen und das Prelude. So bleiben Namen vorhersehbar. Allein in std gibt es mehrere Traits namens Write und Error, und ein Crate, das du später hinzufügst, könnte weitere mitbringen. Würde Rust einen für dich auswählen, könnte eine neue Abhängigkeit stillschweigend ändern, was dein Code bedeutet.

Also sagst du einmal, ganz oben in der Datei, welchen Trait du meinst. Die Hilfe-Zeile übernimmt die Suche für dich und schlägt den Trait vor, den sie gefunden hat. Wie use funktioniert, steht unter Module, und mehr über Display unter Wichtige Traits.

Lösung 1: Die use-Zeile ergänzen, die rustc vorschlägt

Abschnitt betitelt „Lösung 1: Die use-Zeile ergänzen, die rustc vorschlägt“

Nimm diese Lösung, wenn die Hilfe consider importing this trait sagt, und das ist fast immer so. Kopier die Zeile an den Anfang der Datei:

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 ist bei {}", Point { x: -1, y: 7 });
}

Ausgabe:

(3, 4)
Ferris ist bei (-1, 7)
▶ Selbst ausprobieren

Schlägt rustc mehrere Imports vor, lies sie, bevor du einen auswählst. Das sind verschiedene Traits, die zufällig gleich heißen, wie std::fmt::Write und std::io::Write.

Lösung 2: Das Modul importieren und fmt::Display schreiben

Abschnitt betitelt „Lösung 2: Das Modul importieren und fmt::Display schreiben“

Nimm diese Lösung, wenn du Display implementierst, denn dann brauchst du Formatter und Result aus demselben Modul sowieso. Importiere std::fmt einmal und schreib fmt:: vor alle drei. Diesen Stil siehst du in echtem Rust-Code am häufigsten:

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!("{} hat {} Zeichen", label, label.len());
}

Ausgabe:

(3, 4) hat 6 Zeichen
▶ Selbst ausprobieren

Wenn du Display implementierst, bekommst du .to_string() gratis dazu. Du kannst das use auch ganz weglassen und impl std::fmt::Display for Point schreiben. Für eine einzelne Stelle ist das völlig in Ordnung.

Nimm diese Lösung, wenn rustc a trait with a similar name exists sagt (es gibt einen Trait mit ähnlichem Namen). Bei Trait-Namen zählt die Groß- und Kleinschreibung, also sind shape, Shap und Shape drei verschiedene Namen:

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 { // ❌ Tippfehler: Shap
| ^^^^
|
help: a trait with a similar name exists
|
9 | impl Shape for Square { // ❌ Tippfehler: Shap
| +

Das fehlerhafte Programm:

trait Shape {
fn area(&self) -> f64;
}
struct Square {
side: f64,
}
impl Shap for Square { // ❌ Tippfehler: Shap
fn area(&self) -> f64 {
self.side * self.side
}
}
fn main() {
let s = Square { side: 3.0 };
println!("{}", s.area());
}

Das + unter Zeile 9 zeigt den fehlenden Buchstaben. Ergänze ihn:

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

Ausgabe:

9
▶ Selbst ausprobieren

Gibt es keinen ähnlichen Namen und keinen Import-Vorschlag, existiert der Trait noch gar nicht. Definiere ihn dann zuerst mit trait Shape { ... }. Siehe Traits.

Lösung 4: Deinen eigenen Trait aus seinem Modul importieren

Abschnitt betitelt „Lösung 4: Deinen eigenen Trait aus seinem Modul importieren“

Nimm diese Lösung, wenn der Trait von dir stammt, aber in einem anderen Modul liegt. Jedes Modul hat seinen eigenen Gültigkeitsbereich. Ein Trait in mod shapes ist oben in main.rs also erst sichtbar, wenn du ihn importierst:

error[E0405]: cannot find trait `Shape` in this scope
--> src/main.rs:11:6
|
11 | impl Shape for Square { // ❌ `Shape` liegt in `mod shapes`
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use crate::shapes::Shape;
|

Das fehlerhafte Programm:

mod shapes {
pub trait Shape {
fn area(&self) -> f64;
}
}
struct Square {
side: f64,
}
impl Shape for Square { // ❌ `Shape` liegt in `mod shapes`
fn area(&self) -> f64 {
self.side * self.side
}
}
fn main() {
println!("{}", Square { side: 2.0 }.area());
}

Ergänze die use-Zeile und prüfe, ob der Trait pub ist. Ohne pub schlägt schon der Import selbst fehl, mit E0603, „trait is private“ (der Trait ist privat):

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

Ausgabe:

4
▶ Selbst ausprobieren

Dasselbe gilt für Traits aus Crates: impl Serialize for User braucht vorher use serde::Serialize;. Siehe Module.

Box<dyn Error> in main oder einer Hilfsfunktion. fn run() -> Result<(), Box<dyn Error>> ohne Import ergibt cannot find trait `Error` in this scope, mit help: consider importing this trait und use std::error::Error;. Lösung: Ergänze diese Zeile, oder schreib Box<dyn std::error::Error>. Siehe Eigene Fehlertypen.

Trait Bounds bei Generics. fn print_all<T: Display>(items: &[T]) ergibt dasselbe E0405 für Display und zeigt auf den Bound. Lösung: use std::fmt::Display;. Siehe Generics.

Debug ergibt einen anderen Code. impl Debug for Point oder T: Debug ohne Import ist nicht E0405, sondern E0404: expected trait, found derive macro `Debug` (Trait erwartet, Derive-Makro Debug gefunden). Das Prelude enthält das Makro #[derive(Debug)], aber nicht den Trait Debug. Lösung: use std::fmt::Debug; (rustc schlägt es vor), oder einfach #[derive(Debug)], wenn du kein eigenes Format brauchst.

  • E0425: Ein Wert, eine Funktion oder (seit Rust 1.93) ein Typ wird in diesem Gültigkeitsbereich nicht gefunden.
  • E0412: der alte Code für „cannot find type“, heute als E0425 gemeldet.
  • E0433: Der erste Teil eines Pfads wird nicht gefunden, etwa fmt::Display ohne use std::fmt;.
  • E0599: keine Methode gefunden, oft weil der Trait, der die Methode liefert, nicht importiert ist.
  • E0277: Der Trait wurde gefunden, aber dein Typ implementiert ihn nicht.
  • E0404: ein Name, den es gibt, der aber kein Trait ist (wie das Makro Debug), siehe oben.
  • Alle Compilerfehler: die vollständige Liste der Fehlerseiten.

Kurzer Check

1. Du schreibst impl Display for Invoice und bekommst E0405. Was fehlt?

2. Welchen dieser Traits kannst du ohne use-Zeile benutzen?

3. Dein Trait Shape ist in mod shapes definiert, und impl Shape for Square steht in main.rs. Was brauchst du?

Punkte: 0 / 3