Zum Inhalt springen

Rust-Fehler E0412: cannot find type in this scope (Typ nicht gefunden)

E0412 bedeutet: Du hast einen Typnamen geschrieben, den Rust an dieser Stelle nicht sehen kann, zum Beispiel in einer Funktionssignatur wie fn print_invoice(inv: &Invoce). Der Fehler ist sehr häufig und leicht zu beheben: ein Tippfehler, eine fehlende use-Zeile oder ein generisches <T>, das du nicht deklariert hast. Eine Sache verwirrt dich vielleicht zuerst: Seit Rust 1.93 meldet der Compiler diesen Fehler als E0425, mit derselben Meldung cannot find type. Diese Seite behandelt beide, und sie gehört zur Reihe Rust-Compilerfehler einfach erklärt.

So sieht die Meldung ab Rust 1.93 aus (der aktuelle Compiler ist 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 here
2 | fn print_invoice(inv: &Invoce) { // ❌ Tippfehler: Invoce
| ^^^^^^
|
help: a struct with a similar name exists
|
2 | fn print_invoice(inv: &Invoice) { // ❌ Tippfehler: Invoce
| +

Und so sieht dasselbe Programm mit Rust 1.92 oder älter aus – mit der Version, für die die meisten Blogartikel und Antworten auf Stack Overflow geschrieben wurden:

error[E0412]: cannot find type `Invoce` in this scope
--> src/main.rs:2:24
|
1 | struct Invoice { total: u32 }
| -------------- similarly named struct `Invoice` defined here
2 | fn print_invoice(inv: &Invoce) {
| ^^^^^^ help: a struct with a similar name exists: `Invoice`

Auf Deutsch: „Der Typ Invoce ist in diesem Gültigkeitsbereich nicht zu finden.“ Die Notiz sagt „hier ist ein Struct Invoice mit ähnlichem Namen definiert“, und das help sagt: „Es gibt ein Struct mit einem ähnlichen Namen.“

Dieses Programm erzeugt beide Meldungen:

struct Invoice { total: u32 }
fn print_invoice(inv: &Invoce) { // ❌ Tippfehler: Invoce
println!("{}", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

Die offizielle Seite zu E0412 (auf Englisch) beginnt inzwischen mit „this error code is no longer emitted by the compiler“ (dieser Fehlercode wird vom Compiler nicht mehr ausgegeben). Das Problem ist nicht verschwunden, es ist nur zu E0425 umgezogen. Dieser Code deckt auch fehlende Variablen und Funktionen ab. Alles Folgende gilt für beide Codes genauso.

Die ^^^^^^ zeigen auf Invoce in der Signatur. Um diese Funktion zu prüfen, muss Rust wissen, was ein Invoce ist: wie groß es ist und welche Felder es hat. Rust hat sich jeden Typ angesehen, der von Zeile 2 aus sichtbar ist (deine eigenen Structs und Enums, deine use-Zeilen und das Prelude), und nichts mit diesem Namen gefunden.

Die help:-Zeile sagt dir, in welcher Situation du bist:

  • „a struct with a similar name exists“ (es gibt ein Struct mit ähnlichem Namen): ein Tippfehler. Das + zeigt den fehlenden Buchstaben.
  • „consider importing this struct“ (importiere eventuell dieses Struct): Den Typ gibt es woanders, und du brauchst eine use-Zeile.
  • „you might be missing a type parameter“ (dir fehlt vielleicht ein Typparameter): Du hast ein generisches T benutzt, ohne <T> zu deklarieren.
  • gar kein Hinweis: Den Typ gibt es noch nicht. Du hast ihn nicht geschrieben, oder er steht in einer Datei, von der Rust nichts weiß.

Das ist wie ein Rezept, in dem steht: „200 g Invoce hinzufügen“. Der Koch weiß, was Mehl und Zucker sind, aber nicht, was „Invoce“ ist. Also hört er auf, bevor er überhaupt anfängt.

Rust prüft die Signatur jeder Funktion, bevor das Programm läuft. Jeder Parameter- und Rückgabetyp muss einen echten, bekannten Typ nennen. Daran erkennt Rust, wie viel Speicher der Wert braucht und welche Methoden und Felder er hat. Einen Namen, den Rust nicht findet, errät es nicht.

Nur wenige Typnamen sind ohne use überall sichtbar: das Prelude mit String, Vec, Option, Result, Box und ein paar weiteren. Alles andere braucht entweder deine eigene Definition, eine use-Zeile oder einen vollständigen Pfad wie std::num::ParseIntError. Wie Pfade und use funktionieren, erfährst du unter Module.

Warum hat sich der Code geändert? Seit Rust 1.93 meldet rustc einen fehlenden Typ unter E0425 – demselben Code, den es schon für eine fehlende Variable oder Funktion benutzt hat. Die Meldung sagt weiterhin type, du erkennst also immer, welche Art von Name gefehlt hat.

Lösung 1: Die Schreibweise korrigieren oder den Typ definieren

Abschnitt betitelt „Lösung 1: Die Schreibweise korrigieren oder den Typ definieren“

Nimm diese Lösung, wenn rustc einen ähnlichen Namen nennt oder gar keinen Hinweis gibt. Typnamen unterscheiden Groß- und Kleinschreibung: invoice, Invoce und Invoice sind drei verschiedene Namen. Gibt es keinen ähnlichen Namen, schreib zuerst das struct oder enum:

struct Invoice {
total: u32,
}
fn print_invoice(inv: &Invoice) {
println!("Rechnungsbetrag: {} EUR", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

Ausgabe:

Rechnungsbetrag: 120 EUR
▶ Selbst ausprobieren

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

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

Nimm diese Lösung, wenn das help consider importing this struct sagt (oder enum, oder type alias). Typen aus der Standardbibliothek, die nicht im Prelude sind, etwa HashMap, ParseIntError oder Ordering, brauchen eine use-Zeile. Hier gibt eine Funktion einen Fehler beim Parsen zurück:

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

Kopier die vorgeschlagene Zeile an den Anfang der Datei:

use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u8, ParseIntError> {
text.trim().parse()
}
fn main() {
println!("{:?}", parse_age(" 42 "));
println!("{:?}", parse_age("vierzig").is_err());
}

Ausgabe:

Ok(42)
true
▶ Selbst ausprobieren

Hast du HashMap::new() geschrieben (einen Pfad mit ::) statt eines Typs in einer Signatur, ist der Fehler stattdessen E0433, und dieselbe use-Zeile behebt ihn. Schlägt rustc mehrere Importe vor, lies sie, bevor du dich entscheidest: Das sind verschiedene Typen, die nur denselben Namen haben.

Lösung 3: Den generischen Typparameter deklarieren

Abschnitt betitelt „Lösung 3: Den generischen Typparameter deklarieren“

Nimm diese Lösung, wenn das help you might be missing a type parameter sagt. In Rust ist T kein besonderes Wort. Es ist ein Name, den du dir ausdenkst, und du musst ihn in spitzen Klammern hinter dem Funktionsnamen ankündigen. Ohne <T> sucht Rust nach einem echten Typ namens 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 {
| +++

Du bekommst denselben Fehler für jede Stelle, an der T vorkommt. Ergänze <T>, dazu jeden Trait, den die Funktion braucht. Um Elemente mit > zu vergleichen, muss T PartialOrd implementieren:

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

Ausgabe:

100
y
▶ Selbst ausprobieren

Bei Structs ist es genauso: struct Wrapper { items: Vec<Item> } schlägt fehl, außer du schreibst struct Wrapper<Item> oder definierst einen echten Typ Item. Lässt du : PartialOrd weg, bekommst du stattdessen E0369 beim >. Siehe Generics.

Lösung 4: Einen Typ aus einem anderen Modul importieren

Abschnitt betitelt „Lösung 4: Einen Typ aus einem anderen Modul importieren“

Nimm diese Lösung, wenn der Typ dir gehört, aber in einem anderen Modul liegt. Eine häufige Überraschung: Auch ein Modul innerhalb deiner Datei sieht die Typen oben in der Datei nicht. Jedes Modul hat seinen eigenen Gültigkeitsbereich:

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

Das 7 + bedeutet: „Füge diese Zeile im Modul ein, in Zeile 7.“ crate::Order ist der Pfad von der Wurzel deines Crates aus. super::Order („aus dem übergeordneten Modul“) funktioniert auch:

struct Order {
id: u32,
total: u32,
}
mod receipts {
use crate::Order;
pub fn print(order: &Order) -> String {
format!("Bestellung #{}: {} EUR", order.id, order.total)
}
}
fn main() {
let order = Order { id: 7, total: 42 };
println!("{}", receipts::print(&order));
}

Ausgabe:

Bestellung #7: 42 EUR
▶ Selbst ausprobieren

In die andere Richtung funktioniert es genauso: Ein Typ aus mod shop braucht pub struct Product und use crate::shop::Product; (oder den vollständigen Pfad shop::Product), bevor main ihn benutzen kann. Am häufigsten begegnet dir das in mod tests, wo use super::*; ganz oben alles aus dem übergeordneten Modul importiert.

Ein Typ aus einer Datei, die du nicht deklariert hast. fn save(user: models::User) mit einer Datei src/models.rs, aber ohne Zeile mod models;, ergibt weder E0412 noch E0425, sondern E0433: cannot find module or crate `models` in this scope (Modul oder Crate models nicht gefunden). Lösung: Schreib mod models; an den Anfang von main.rs und mach das Struct pub.

Self außerhalb eines impl. fn new_counter() -> Self auf oberster Ebene ergibt einen eigenen Code, E0411: cannot find type `Self` in this scope, mit der Markierung `Self` is only available in impls, traits, and type definitions (Self gibt es nur in impls, Traits und Typdefinitionen). Lösung: Verschieb die Funktion in impl Counter { ... }, oder schreib Counter statt Self.

Ein Trait statt eines Typs. impl Display for Point ohne Import von Display ergibt E0405, cannot find trait `Display` in this scope, mit help: consider importing this trait und use std::fmt::Display;. Gleiche Idee, gleiche Lösung: Ergänze die use-Zeile. Siehe Traits.

  • E0425: Wert oder Funktion nicht gefunden, und seit Rust 1.93 auch Typ. Diesen Code siehst du heute tatsächlich.
  • E0433: Der erste Teil eines Pfads wie HashMap::new() oder models::User wird nicht gefunden.
  • E0432: unresolved import (Import nicht gefunden), wenn die use-Zeile selbst ins Leere zeigt.
  • E0603: Der Typ wurde gefunden, ist aber nicht pub.
  • E0405 (Trait nicht gefunden) und E0411 (Self außerhalb eines impl): die nahen Verwandten von oben.
  • Alle Compilerfehler: die vollständige Liste der Fehlerseiten.

Kurzer Check

1. Du folgst einem Tutorial, das error[E0412]: cannot find type zeigt, aber dein Compiler gibt error[E0425]: cannot find type aus. Warum?

2. fn first(items: &[T]) -> &T ergibt cannot find type T. Wie behebst du das?

3. Eine Funktion in mod billing benutzt Order, ein Struct, das oben in main.rs definiert ist. Welche Zeile im Modul behebt das?

Punkte: 0 / 3