Rust-Fehler E0424: expected value, found module `self` (self fehlt)
E0424 bedeutet: Du hast self in einer Funktion geschrieben, die gar keinen self-Parameter hat. Es gibt also kein „self“, auf das Rust zeigen könnte. Das passiert sehr oft, besonders wenn du aus Java, C# oder JavaScript kommst, wo this immer einfach da ist. Die Lösung ist meistens ein einziges Wort: Ergänze &self in der Parameterliste der Funktion. Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0424]: expected value, found module `self` --> src/main.rs:7:32 |6 | fn describe() { | -------- this function doesn't have a `self` parameter7 | println!("Player: {}", self.name); // ❌ welcher Spieler? | ^^^^ `self` value is a keyword only available in methods with a `self` parameter |help: add a `self` receiver parameter to make the associated `fn` a method |6 | fn describe(&self) { | +++++
error[E0599]: no method named `describe` found for struct `Player` in the current scope --> src/main.rs:13:10 |13 | hero.describe(); | ^^^^^^^^ this is an associated function, not a method„Expected value, found module self“ heißt „Wert erwartet, Modul self gefunden“. Das help schlägt vor, &self als Parameter zu ergänzen, damit aus der Funktion eine Methode wird.
Dieses Programm erzeugt den Fehler:
struct Player { name: String,}
impl Player { fn describe() { println!("Player: {}", self.name); // ❌ welcher Spieler? }}
fn main() { let hero = Player { name: String::from("Ferris") }; hero.describe();}Der zweite Fehler, E0599, ist nur eine Folge des ersten. Behebst du E0424, verschwindet er auch.
Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Schau dir die beiden Markierungen an, die rustc an deinen Code setzt:
- Zeile 6:
fn describe()hat leere Klammern. rustc merkt an: „this function doesn’t have aselfparameter“ (diese Funktion hat keinenself-Parameter). - Zeile 7:
self.namefragt nach dem Namen „des Spielers, für den die Funktion aufgerufen wurde“. Aberdescribehat keinen Spieler bekommen. Hier bedeutetselfalso nichts.
Eine Funktion in einem impl-Block ohne self-Parameter ist eine assoziierte Funktion (Associated Function). Sie gehört zum Typ (Player::describe()), nicht zu einem bestimmten Wert. Eine Funktion mit self-Parameter ist eine Methode, und nur Methoden dürfen self sagen.
Stell dir ein Formular vor, auf dem steht: „Trag hier deinen eigenen Namen ein.“ Das ergibt erst Sinn, wenn jemand das Formular in der Hand hält. describe() ist ein Formular, das niemand in der Hand hält.
Warum steht da „found module self“? In Rust hat self eine zweite Bedeutung: das aktuelle Modul, wie in use self::helpers;. Wenn es keinen self-Wert gibt, greift rustc auf diese Bedeutung zurück und beschwert sich dann, dass ein Modul kein Wert ist. Das Wort „module“ kannst du ignorieren. Das eigentliche Problem ist der fehlende Parameter.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“In Rust ist nichts versteckt. Java und C# geben jeder nicht-statischen Methode ein unsichtbares this. Rust lässt dich self als ersten Parameter hinschreiben. Dabei sagst du auch, wie die Methode den Wert bekommt: nur zum Ansehen, zum Ändern oder als Eigentum. Diese Wahl gehört zu den Regeln für Borrowing (Ausleihen), deshalb muss sie sichtbar sein.
So sehen alle, die deinen Code lesen, und auch der Compiler genau, was eine Methode mit ihrem Wert macht. fn summary(&self) verspricht, nichts zu ändern. fn add(&mut self, ...) warnt, dass sich etwas ändert. fn checkout(self) verbraucht den Wert. Der Compiler prüft diese Versprechen dann für dich. Methoden und impl-Blöcke erklärt die Seite Structs.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: &self, &mut self oder self ergänzen
Abschnitt betitelt „Lösung 1: &self, &mut self oder self ergänzen“Nimm diese Lösung, wenn die Funktion mit einem vorhandenen Wert arbeiten soll. In den meisten Fällen ist das die richtige Wahl. Ergänze den Parameter, den rustc vorschlägt, und ruf die Methode mit einem Punkt auf:
struct Player { name: String,}
impl Player { fn describe(&self) { println!("Player: {}", self.name); }}
fn main() { let hero = Player { name: String::from("Ferris") }; hero.describe();}Ausgabe:
Player: Ferrisrustc schlägt immer &self vor, aber es gibt drei Arten. Nimm die, die zu dem passt, was die Methode tut:
| Parameter | Die Methode … | Typische Namen |
|---|---|---|
&self |
liest den Wert nur | summary, len, is_empty, describe |
&mut self |
ändert den Wert | add, push, reset, level_up |
self |
verbraucht den Wert (übernimmt die Ownership) | into_..., finish, build, checkout |
Hier sind alle drei an einem Typ:
struct Order { items: Vec<String>,}
impl Order { fn summary(&self) -> String { format!("{} Artikel: {}", self.items.len(), self.items.join(", ")) }
fn add(&mut self, item: &str) { self.items.push(item.to_string()); }
fn checkout(self) -> Vec<String> { self.items }}
fn main() { let mut order = Order { items: Vec::new() }; order.add("Kaffee"); order.add("Brezel"); println!("{}", order.summary()); let packed = order.checkout(); // hier wird order verbraucht println!("Eingepackt: {:?}", packed);}Ausgabe:
2 Artikel: Kaffee, BrezelEingepackt: ["Kaffee", "Brezel"]Wenn du &self wählst, die Methode aber ein Feld ändert, sagt dir der Compiler das sofort (E0594 „cannot assign to self.count, which is behind a & reference“, oder E0596 bei Aufrufen wie push). Wechsle dann zu &mut self. Im Zweifel fang mit &self an. self brauchst du am seltensten.
Lösung 2: Als Type::method(&value) aufrufen
Abschnitt betitelt „Lösung 2: Als Type::method(&value) aufrufen“Hat eine Funktion einen self-Parameter, kannst du sie auf zwei Arten aufrufen. hero.label() und Player::label(&hero) bedeuten genau dasselbe: Der Wert vor dem Punkt wird zum ersten Argument. Die Punkt-Schreibweise benutzt du fast immer. Die Form mit Type:: ist praktisch, wenn du die Methode selbst weitergeben willst, zum Beispiel an map:
struct Player { name: String, level: u32,}
impl Player { fn label(&self) -> String { format!("{} (Level {})", self.name, self.level) }}
fn main() { let hero = Player { name: String::from("Ferris"), level: 3 }; println!("{}", hero.label()); println!("{}", Player::label(&hero)); // derselbe Aufruf
let team = vec![hero, Player { name: String::from("Corro"), level: 5 }]; let labels: Vec<String> = team.iter().map(Player::label).collect(); println!("{:?}", labels);}Ausgabe:
Ferris (Level 3)Ferris (Level 3)["Ferris (Level 3)", "Corro (Level 5)"]Was nicht geht, ist Player::label() ohne Wert: Eine Methode braucht immer ihr self. Lässt du es weg, bekommst du E0061, „this function takes 1 argument but 0 arguments were supplied“ (die Funktion erwartet 1 Argument, aber 0 wurden übergeben).
Lösung 3: Übergib, was die Funktion braucht
Abschnitt betitelt „Lösung 3: Übergib, was die Funktion braucht“Nimm diese Lösung, wenn es noch keinen Wert gibt oder wenn die Funktion gar nicht in einem impl-Block steht.
Der klassische Fall ist ein Konstruktor. new erzeugt den Wert erst, also gibt es kein self, aus dem man lesen könnte. Gib new die Startdaten als normale Parameter und bau das Struct mit Self { ... }:
struct Counter { count: u32, step: u32,}
impl Counter { fn new(step: u32) -> Self { Self { count: 0, step } }
fn tick(&mut self) { self.count += self.step; }}
fn main() { let mut counter = Counter::new(5); counter.tick(); counter.tick(); println!("Zählerstand: {}", counter.count);}Ausgabe:
Zählerstand: 10Achte auf die Großschreibung: Self (großes S) ist der Typ, also baut Self { ... } einen neuen Wert. self (kleines s) ist der Wert, für den eine Methode aufgerufen wurde.
Dieselbe Idee hilft bei einer freien Funktion, also einer außerhalb jedes impl-Blocks. rustc formuliert es dort etwas anders: „this function can’t have a self parameter“ (diese Funktion kann keinen self-Parameter haben). Übergib das Struct stattdessen als Referenz:
struct Cart { items: Vec<u32>,}
fn total(cart: &Cart) -> u32 { cart.items.iter().sum()}
// Aufruf: total(&cart)Oder verschieb total in impl Cart und gib ihr &self, wie in Lösung 1. Beides ist in Ordnung. Eine Methode liest sich natürlicher, wenn es in der Funktion klar „um“ einen Warenkorb geht.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“In new. Schreibst du self.count = 0; in fn new() -> Self, gibt es E0424. Der Vorschlag von rustc, fn new(&self) -> Self, ergibt hier keinen Sinn: Du bräuchtest einen Zähler, um einen Zähler zu bauen. Lösung: Bau den Wert mit Self { count: 0 }, wie in Lösung 3.
In einem Closure in einer assoziierten Funktion. Das Problem ist nicht das Closure, sondern die Funktion drumherum:
error[E0424]: expected value, found module `self` --> src/main.rs:8:35 |7 | fn sale_prices(prices: &[u32]) -> Vec<u32> { | ----------- this function doesn't have a `self` parameter8 | prices.iter().map(|p| p - self.discount).collect() | ^^^^ `self` value is a keyword only available in methods with a `self` parameterLösung: Mach eine Methode daraus, fn sale_prices(&self, prices: &[u32]), oder übergib die Zahl, fn sale_prices(prices: &[u32], discount: u32). Siehe Closures.
In main oder einer Hilfsfunktion. Außerhalb eines impl-Blocks funktioniert self nie. Lösung: Übergib das Struct als Parameter (total(&cart)), oder ruf eine Methode darauf auf (cart.total()).
Wenn du „statische“ Methoden aus C# oder Java gewohnt bist. Eine assoziierte Funktion ohne self ist Rusts Version einer statischen Methode. Willst du die Version für eine Instanz, musst du den self-Parameter selbst ergänzen. Siehe Rust für C#-Entwickler.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0425: der umgekehrte Fehler. Du bist in einer Methode, hast aber
countstattself.countgeschrieben. - E0599: „no method named … found“ (keine Methode mit diesem Namen). Erscheint oft direkt nach E0424, weil man eine Funktion ohne
selfnicht mit einem Punkt aufrufen kann. - E0061: falsche Anzahl von Argumenten, zum Beispiel
Player::label()ohne den Wert. - E0596: Du hast
&selfergänzt, aber die Methode ändert ein Feld, also braucht sie&mut self. Eine Zuweisung an ein Feld ergibt in diesem Fall E0594. - Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. In impl Player ergibt fn heal() { self.hp += 10; } den Fehler E0424. Was ist die beste Lösung?
2. Warum kann fn new() -> Self nicht self.name benutzen?
3. fn label(&self) -> String ist für Player definiert. Welcher Aufruf ist dasselbe wie hero.label()?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0424 – Rust error codes index (auf Englisch): die offizielle Erklärung dieses Fehlers, mit einem kurzen Beispiel.
- Methoden – Das Rust-Buch:
&self,&mut selfundself, dazu assoziierte Funktionen wienew. - Associated functions and methods – Rust by Example (auf Englisch): ausführbare Beispiele für beide Arten, direkt nebeneinander.
- Das Schlüsselwort
self– Doku der Standardbibliothek (auf Englisch): beide Bedeutungen vonself, als Empfänger einer Methode und als aktuelles Modul. - Associated items – The Rust Reference (auf Englisch): die genauen Regeln für Methoden, Empfänger und assoziierte Funktionen.