Rust-Fehler E0592: duplicate definitions with name X (doppelte Methode)
E0592 bedeutet: Derselbe Typ hat zwei Methoden, assoziierte Funktionen oder Konstanten mit demselben Namen, geschrieben in impl-Blöcken. Ein Typ darf beliebig viele impl-Blöcke haben, aber alle teilen sich eine einzige Namensliste. Jeder Name darf also nur einmal vorkommen. Meistens kommt der Fehler von Kopieren und Einfügen, einem Merge oder einem zweiten impl-Block in einer anderen Datei. Die Lösung: Behalte einen, oder gib dem anderen einen neuen Namen. (Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.)
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0592]: duplicate definitions with name `reset` --> src/main.rs:10:5 |10 | fn reset(&mut self) { | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `reset`...16 | fn reset(&mut self) { // ❌ `reset` ist oben schon definiert | ------------------- other definition for `reset`Auf Deutsch: „Doppelte Definitionen mit dem Namen reset.“ Die ^^^-Zeile markiert eine Definition, die ----Zeile die „andere Definition“.
Dieses Programm erzeugt den Fehler:
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Counter { count: 0 } }
fn reset(&mut self) { self.count = 0; }}
impl Counter { fn reset(&mut self) { // ❌ `reset` ist oben schon definiert self.count = 0; }}
fn main() { let mut c = Counter::new(); c.reset(); println!("{}", c.count);}rustc meldet beim Aufruf c.reset() außerdem E0034, „multiple applicable items in scope“ (mehrere passende Elemente im Gültigkeitsbereich), weil es nicht weiß, welches der beiden reset du meinst. Das ist ein Folgefehler: Behebst du E0592, verschwindet E0034 gleich mit.
Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Die Überschrift nennt den Namen, der doppelt definiert ist (reset). Das ^^^ markiert die eine Definition, die ----Zeile die „other definition“ (die andere Definition). rustc zeigt die Zeilennummern von beiden, also kannst du direkt hinspringen. Liegen sie weit auseinander, bedeutet das ... dazwischen nur „einige Zeilen ausgelassen“.
Es spielt keine Rolle, dass die beiden reset in verschiedenen impl Counter-Blöcken stehen, oder sogar in verschiedenen Dateien deines Crates. Für Rust sind sie alle Methoden desselben Typs, also muss Counter::reset genau eine Funktion bedeuten. Dieselbe Regel gilt für assoziierte Konstanten: Zwei const MAX: u32 für einen Typ ergeben ebenfalls E0592.
Das ist wie eine Kontaktliste im Handy mit zwei Einträgen namens „Mama“. Wenn du sagst „Ruf Mama an“, welche Nummer soll es wählen?
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“Methoden auf mehrere impl-Blöcke zu verteilen, ist erlaubt und oft nützlich: ein Block für Konstruktoren, einer für Getter, einer hinter #[cfg(test)]. Siehe Verhalten mit Methoden hinzufügen. Aber wenn du c.reset() oder Counter::reset(&mut c) aufrufst, muss Rust eine Funktion finden. Gäbe es zwei, hinge es von Details ab, die niemand beim Lesen des Aufrufs sieht, welche davon läuft.
Deshalb lehnt Rust schon die Definition ab, nicht erst den Aufruf. Das fängt einen echten Bug ab: Bei einer kopierten Methode behebst du vielleicht ein Problem in der einen Kopie, während die andere weiterläuft. Rust sorgt dafür, dass es immer nur eine Version gibt, die du reparieren musst.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: Die Kopie löschen und eine Definition behalten
Abschnitt betitelt „Lösung 1: Die Kopie löschen und eine Definition behalten“Nimm diese Lösung in den meisten Fällen. Tun beide Kopien dasselbe (Kopieren und Einfügen, ein unordentlicher Merge, eine Methode, die du verschoben, aber nicht entfernt hast), lösch eine davon. Vergleich vorher die beiden Rümpfe: Hat einer eine Korrektur, die dem anderen fehlt, behalte diesen. Fasst du die impl-Blöcke zu einem zusammen, fallen Duplikate in Zukunft auch leichter auf.
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Counter { count: 0 } }
fn increment(&mut self) { self.count += 1; }
fn reset(&mut self) { // ✅ nur ein `reset` für `Counter` self.count = 0; }}
fn main() { let mut c = Counter::new(); c.increment(); c.increment(); println!("vor reset: {}", c.count); c.reset(); println!("nach reset: {}", c.count);}Ausgabe:
vor reset: 2nach reset: 0Findest du die zweite Definition nicht, durchsuch das ganze Projekt: grep -rn "fn reset" src/. Ein impl Counter-Block kann in jedem Modul deines Crates stehen.
Lösung 2: Eine der beiden umbenennen
Abschnitt betitelt „Lösung 2: Eine der beiden umbenennen“Nimm diese Lösung, wenn die beiden Definitionen Verschiedenes tun. Rust kennt kein Überladen: Du kannst keine zwei Methoden mit demselben Namen und verschiedenen Parametern haben, etwa reset() und reset(start: u32). Auch das ist E0592. Gib jeder einen Namen, der sagt, was sie tut:
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Counter { count: 0 } }
fn reset(&mut self) { self.count = 0; }}
impl Counter { fn reset_to(&mut self, start: u32) { // ✅ anderer Name für anderes Verhalten self.count = start; }}
fn main() { let mut c = Counter::new(); c.reset_to(10); println!("nach reset_to(10): {}", c.count); c.reset(); println!("nach reset(): {}", c.count);}Ausgabe:
nach reset_to(10): 10nach reset(): 0Die üblichen Namensmuster in Rust helfen dabei: new und with_capacity, from_str und from_bytes, get und get_mut. Willst du wirklich einen Namen für mehrere Argumenttypen, nimm einen generischen Parameter oder einen Trait, etwa fn reset_to(&mut self, start: impl Into<u32>). Siehe Generics.
Lösung 3: Verhindern, dass sich generische impl-Blöcke überschneiden
Abschnitt betitelt „Lösung 3: Verhindern, dass sich generische impl-Blöcke überschneiden“Nimm diese Lösung, wenn eine der beiden Definitionen in einem generischen Block wie impl<T> Wrapper<T> steht. Dieser Block deckt auch Wrapper<i32> ab, also ist ein zweites impl Wrapper<i32> mit demselben Methodennamen ein Duplikat:
error[E0592]: duplicate definitions with name `describe` --> src/main.rs:4:5 | 4 | fn describe(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `describe`...10 | fn describe(&self) -> String { | ---------------------------- other definition for `describe`Das Programm dazu:
struct Wrapper<T>(T);
impl<T> Wrapper<T> { fn describe(&self) -> String { String::from("irgendetwas") }}
impl Wrapper<i32> { fn describe(&self) -> String { format!("die Zahl {}", self.0) }}
fn main() { println!("{}", Wrapper(5).describe());}Rust erlaubt nicht, dass ein spezielles impl ein generisches überschreibt (dieses Feature heißt Specialization und ist nicht stabil). Es gibt zwei gute Auswege: Schreib impl-Blöcke nur für konkrete Typen, damit sie sich nicht überschneiden können, oder pack das Verhalten in einen Trait und implementiere ihn einmal pro Typ:
struct Wrapper<T>(T);
// Variante A: impl-Blöcke für konkrete Typen überschneiden sich nieimpl Wrapper<i32> { fn describe(&self) -> String { format!("die Zahl {}", self.0) }}
impl Wrapper<&str> { fn describe(&self) -> String { format!("der Text \"{}\"", self.0) }}
// Variante B: ein Trait, einmal pro Typ implementierttrait Label { fn label(&self) -> String;}
impl Label for i32 { fn label(&self) -> String { format!("Ganzzahl {}", self) }}
impl Label for bool { fn label(&self) -> String { format!("Flag {}", self) }}
impl<T: Label> Wrapper<T> { fn label(&self) -> String { self.0.label() // eine generische Methode, der Teil pro Typ steckt im Trait }}
fn main() { println!("{}", Wrapper(5).describe()); println!("{}", Wrapper("hi").describe()); println!("{}", Wrapper(7).label()); println!("{}", Wrapper(true).label());}Ausgabe:
die Zahl 5der Text "hi"Ganzzahl 7Flag trueDie Trait-Version ist auf lange Sicht meistens das bessere Design: Einen neuen Typ zu unterstützen, ist nur ein weiteres impl Label for .... Siehe Traits.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“Eine Test-Hilfsfunktion in einem zweiten impl-Block. Du schreibst impl Counter { fn new() -> Self { ... } } in #[cfg(test)] mod tests, um Testwerte zu bauen, aber Counter::new gibt es schon. Auch der Test-Block ist ein impl Counter. Lösung: Nenn sie etwa fn for_test(), oder benutze das echte new. Siehe Tests.
Nach einem Merge oder Refactoring. Zwei Branches haben beide ein fn len(&self) hinzugefügt, oder eine Methode wurde in eine neue Datei verschoben, und die alte Kopie ist geblieben. rustc zeigt beide Zeilennummern; behalte die bessere.
Eine Trait-Methode mit demselben Namen ist in Ordnung. impl Counter { fn reset(&mut self) } zusammen mit impl Resettable for Counter { fn reset(&mut self) } ist kein E0592: Die eine ist die eigene Methode des Typs, die andere gehört zum Trait, und c.reset() ruft die eigene Methode des Typs auf. Auch zwei Traits mit demselben Methodennamen kompilieren, aber der Aufruf c.reset() ergibt dann E0034. Das löst du mit Resettable::reset(&mut c).
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0034: multiple applicable items in scope: der Folgefehler beim Aufruf, und der Fehler für zwei Traits mit demselben Methodennamen.
- E0428: the name is defined multiple times: derselbe Fehler für Elemente in einem Modul, etwa zwei
struct Counteroder zwei freie Funktionenfn main. - E0599: no method named x found: das umgekehrte Problem, eine Methode, die es gar nicht gibt.
- E0255: Name schon von einem Import belegt und E0252: Name doppelt importiert: doppelte Namen, die durch
useentstehen. - Alle Compilerfehler einfach erklärt
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Ein Typ hat zwei impl-Blöcke. Dürfen beide eine Methode namens reset enthalten?
2. Du willst area() und area(scale: f64). Was machst du in Rust?
3. Warum kollidieren impl<T> Wrapper<T> und impl Wrapper<i32>, wenn beide describe definieren?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0592 – Rust error codes index (auf Englisch): die offizielle Erklärung dieses Fehlers.
- Methoden – Das Rust-Buch: Methoden, assoziierte Funktionen und mehrere
impl-Blöcke. - Generische Datentypen – Das Rust-Buch:
impl<T> Point<T>nebenimpl Point<f32>, und wie die beiden zusammenhängen. - Implementations – The Rust Reference (auf Englisch): die genauen Regeln für eigene
impl-Blöcke und ihre assoziierten Elemente. - E0034 – Rust error codes index (auf Englisch): die offizielle Seite zum Folgefehler „multiple applicable items“.