Zum Inhalt springen

Rust-Fehler E0411: cannot find type Self in this scope (Self ohne impl)

E0411 bedeutet: Du hast Self an eine Stelle geschrieben, an der Rust nicht weiß, wofür es steht. Self ist eine Abkürzung für „den Typ, um den es in diesem impl-Block (oder Trait) geht“. Es funktioniert also nur innerhalb eines impl, eines Traits oder einer Typdefinition. Die übliche Ursache ist ein Konstruktor wie fn new() -> Self, der auf der obersten Ebene der Datei steht, oder eine Methode, die du aus ihrem impl-Block herauskopiert hast. Der Fehler ist häufig und schnell behoben. Anders als E0412, der seit Rust 1.93 als E0425 gemeldet wird, hat sich dieser Code nicht geändert: Auch rustc 1.97 gibt E0411 aus. Die Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.

error[E0411]: cannot find type `Self` in this scope
--> src/main.rs:5:21
|
5 | fn new_counter() -> Self { // ❌ `Self` außerhalb eines `impl`
| ----------- ^^^^ `Self` is only available in impls, traits, and type definitions
| |
| `Self` not allowed in a function

Auf Deutsch: „Der Typ Self wurde in diesem Gültigkeitsbereich nicht gefunden.“

Dieses Programm erzeugt den Fehler:

struct Counter {
count: u32,
}
fn new_counter() -> Self { // ❌ `Self` außerhalb eines `impl`
Counter { count: 0 }
}
fn main() {
let c = new_counter();
println!("{}", c.count);
}

rustc zeigt in Zeile 5 auf zwei Dinge:

  1. Die ^^^^ unter Self: „Self is only available in impls, traits, and type definitions“ (Self gibt es nur in impls, Traits und Typdefinitionen). Das ist die Regel in einer Zeile.
  2. Die ----- unter new_counter: „Self not allowed in a function“ (Self ist in einer Funktion nicht erlaubt). Das ist hier der Grund: new_counter ist eine normale Funktion und gehört zu keinem impl.

Du weißt vielleicht, dass new_counter einen Counter zurückgibt, weil du gerade Counter { count: 0 } geschrieben hast. Aber Rust liest nicht den Rumpf der Funktion, um zu erraten, was Self bedeutet. Self bekommt seine Bedeutung nur von einem umgebenden impl Counter { ... } oder trait ... { ... }, und hier gibt es keins.

Das ist wie das Wort „hier“ auf einem Notizzettel. Auf einem Stadtplan ergibt „Sie sind hier“ Sinn. Auf einem Zettel, der auf dem Küchentisch liegt, weiß niemand, wo „hier“ ist.

Self ist kein eigener Typ. Es ist ein Platzhalter, den jedes impl oder jeder Trait füllt: In impl Counter bedeutet Self Counter, in impl Timer bedeutet es Timer, und in einem Trait bedeutet es „der Typ, der diesen Trait implementiert“. Genau das macht es nützlich: Du kannst das Struct umbenennen oder eine Methode in ein anderes impl kopieren, und Self wandert mit.

Eine freie Funktion gehört zu keinem Typ, also gibt es nichts, womit der Platzhalter gefüllt werden könnte. Rust könnte versuchen, es aus dem Rumpf zu erraten. Dann würde eine Signatur aber vom Code in ihrem Inneren abhängen, und Rust prüft Signaturen absichtlich für sich allein. Wo fn new() -> Self normalerweise hingehört, siehst du unter Structs.

Lösung 1: Die Funktion in einen impl-Block verschieben

Abschnitt betitelt „Lösung 1: Die Funktion in einen impl-Block verschieben“

Nimm diese Lösung in den meisten Fällen. Eine Funktion, die einen Typ erzeugt oder mit ihm arbeitet, gehört in den impl-Block dieses Typs, und dort funktioniert Self so, wie du es erwartet hast. Du rufst sie mit Counter::new() auf:

struct Counter {
count: u32,
}
impl Counter {
fn new() -> Self {
Self { count: 0 }
}
fn increment(&mut self) {
self.count += 1;
}
}
fn main() {
let mut c = Counter::new();
c.increment();
c.increment();
println!("{}", c.count);
}

Ausgabe:

2
▶ Selbst ausprobieren

Innerhalb des impl kannst du Self sowohl als Typ (-> Self) als auch zum Erzeugen eines Werts (Self { count: 0 }) benutzen. Siehe Structs.

Lösung 2: Den Namen des Typs statt Self schreiben

Abschnitt betitelt „Lösung 2: Den Namen des Typs statt Self schreiben“

Nimm diese Lösung, wenn die Funktion eine freie Funktion bleiben soll, zum Beispiel eine Hilfsfunktion, die mehrere Typen erzeugt, oder eine, die in einem anderen Modul liegt. Schreib einfach den echten Typ, Counter, dorthin, wo Self stand:

struct Counter {
count: u32,
}
fn new_counter(start: u32) -> Counter {
Counter { count: start }
}
fn reset(c: &mut Counter) {
c.count = 0;
}
fn main() {
let mut c = new_counter(10);
println!("{}", c.count);
reset(&mut c);
println!("{}", c.count);
}

Ausgabe:

10
0
▶ Selbst ausprobieren

Das ist auch die Lösung für ein fn reset(c: &mut Self), das du aus einem impl herauskopiert hast: Jedes Self in der Signatur und im Rumpf wird zu Counter.

Lösung 3: Einen generischen Typ benutzen, wenn du „irgendeinen Typ“ meinst

Abschnitt betitelt „Lösung 3: Einen generischen Typ benutzen, wenn du „irgendeinen Typ“ meinst“

Nimm diese Lösung, wenn du mit Self „den Typ, den der Aufrufer haben will“ gemeint hast. Das ist eine Aufgabe für ein generisches T, nicht für Self. Deklariere <T> mit den Traits, die die Funktion braucht. Hier sorgt T: Default dafür, dass die Funktion einen Startwert jedes beliebigen Typs erzeugen kann:

fn fresh_pair<T: Default>() -> (T, T) {
(T::default(), T::default())
}
fn main() {
let numbers: (u32, u32) = fresh_pair();
let words: (String, String) = fresh_pair();
println!("{:?}", numbers);
println!("{:?}", words);
}

Ausgabe:

(0, 0)
("", "")
▶ Selbst ausprobieren

Soll jeder Typ selbst entscheiden, wie er erzeugt wird, gehört die Funktion in einen Trait: trait Reset { fn fresh() -> Self; }. In einem Trait bedeutet Self „der Typ, der ihn implementiert“. Siehe Generics und Traits.

Self { ... } in main oder in einer freien Funktion. let c = Self { count: 0 }; ergibt E0411 mit einer etwas anderen Überschrift: cannot find struct, variant or union type `Self` in this scope (Struct-, Varianten- oder Union-Typ Self nicht gefunden). Lösung: Schreib Counter { count: 0 }, oder ruf Counter::new() auf.

Eine Hilfsfunktion, die in einer Methode verschachtelt ist. Enthält eine Methode in impl Counter ihre eigene fn helper() -> Self, bekommst du einen anderen Code, E0401: can't use `Self` from outer item (Self aus dem äußeren Element ist hier nicht nutzbar). Eine Funktion in einer Funktion erbt das äußere impl nicht. Lösung: Schreib in der inneren Funktion Counter, benutze ein Closure, oder verschieb helper als eigene Methode nach oben in das impl.

Self und self verwechseln. Das große Self ist der Typ, das kleine self ist der Wert, auf dem eine Methode aufgerufen wird. self außerhalb einer Methode ist ein anderer Fehler, E0424. Lösung für beide: Sorg dafür, dass der Code im richtigen impl-Block steht.

  • E0424: self (klein, der Wert) außerhalb einer Methode benutzt.
  • E0425: Ein Wert, eine Funktion oder (seit Rust 1.93) ein Typ mit einem normalen Namen wird nicht gefunden.
  • E0412: der alte Code für „cannot find type“, heute als E0425 gemeldet.
  • E0405: Ein Trait wird nicht gefunden, meistens fehlt eine use-Zeile.
  • E0401: Self aus einem äußeren impl in einer verschachtelten Funktion benutzt, siehe oben.
  • Alle Compilerfehler: die vollständige Liste der Fehlerseiten.

Kurzer Check

1. Wo kannst du Self als Typ benutzen?

2. fn make_user() -> Self auf oberster Ebene ergibt E0411. Was ist die übliche Lösung?

3. Was erzeugt Self { count: 0 } innerhalb von impl Counter?

Punkte: 0 / 3