Rust-Fehler E0255: the name is defined multiple times (Import vs. eigener Typ)
E0255 bedeutet: Eine use-Zeile und etwas, das du selbst definiert hast, haben denselben Namen. Der klassische Fall: Du importierst oben in der Datei std::io::Error und schreibst später dein eigenes enum Error. Ein Name darf in Rust nicht zwei Dinge bedeuten, also bricht der Compiler ab. Der Fehler ist sehr häufig, sobald du deine ersten eigenen Fehlertypen schreibst, und die Lösung ist eine kurze Zeile. Anders als bei E0412 hat sich dieser Code in den letzten Versionen nicht geändert: Auch rustc 1.97 meldet ihn als E0255. Die Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0255]: the name `Error` is defined multiple times --> src/main.rs:3:1 |1 | use std::io::Error; | -------------- previous import of the type `Error` here2 |3 | enum Error { // ❌ gleicher Name wie der Import in Zeile 1 | ^^^^^^^^^^ `Error` redefined here | = note: `Error` must be defined only once in the type namespace of this modulehelp: you can use `as` to change the binding name of the import |1 | use std::io::Error as OtherError; | +++++++++++++
warning: unused import: `std::io::Error` --> src/main.rs:1:5 |1 | use std::io::Error; | ^^^^^^^^^^^^^^Auf Deutsch: „Der Name Error ist mehrfach definiert.“ Die note sagt: „Error darf im Typ-Namensraum dieses Moduls nur einmal definiert sein.“ Die Warnung darunter heißt „ungenutzter Import“.
Dieses Programm erzeugt den Fehler:
use std::io::Error;
enum Error { // ❌ gleicher Name wie der Import in Zeile 1 EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } if name.len() > 10 { return Err(Error::TooLong(name.len())); } Ok(())}
fn main() { match check_name("") { Ok(()) => println!("Name ist in Ordnung"), Err(Error::EmptyName) => println!("Name ist leer"), Err(Error::TooLong(n)) => println!("Name hat {} Buchstaben, erlaubt sind höchstens 10", n), }}Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“rustc zeigt auf drei Dinge:
- Die
----Zeile (Zeile 1): „previous import of the typeErrorhere“ (hier wurde der TypErrorschon importiert). Dieuse-Zeile hat den NamenErrorbereits in dieses Modul gebracht. - Die
^^^-Zeile (Zeile 3): „Errorredefined here“ (Errorhier erneut definiert). Dein eigenesenum Errorwill denselben Namen haben. - Das
help:zeigt einen Ausweg: Gib dem Import mitaseinen anderen lokalen Namen.
Die Warnung warning: unused import darunter ist ein nützlicher Hinweis. Sie bedeutet: Nichts in deinem Code benutzt std::io::Error wirklich (jedes Error in diesem Programm meint dein Enum). Dann kannst du Zeile 1 einfach löschen. Brauchst du beide, lies weiter.
Die Notiz erwähnt den type namespace (Typ-Namensraum). Typen, Traits und Module teilen sich eine Liste von Namen, Funktionen, Konstanten und Statics eine andere. Deshalb ergibt use std::mem::swap; zusammen mit deinem eigenen fn swap denselben Fehler, nur im „value namespace“ (Werte-Namensraum).
Stell dir eine Schulklasse mit zwei Kindern namens Alex vor. Die Lehrerin kann nicht mehr einfach „Alex“ rufen. Einer von beiden braucht einen Spitznamen, etwa „Alex B.“ – und genau das gibt as einem Import.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“Ein Name in einem Modul zeigt auf genau ein Element. Liest Rust in Zeile 10 Error::EmptyName, muss es wissen, welches Error du meinst, und es weigert sich zu raten. Würde es stillschweigend dein Enum nehmen, wäre deine use-Zeile wirkungslos. Würde es io::Error nehmen, käme man an dein Enum nicht mehr heran. In beiden Fällen würde eine stille Wahl einen Fehler verstecken.
Deshalb ist E0255 ein Geschwister von E0428 (zwei deiner eigenen Elemente mit einem Namen) und E0252 (zwei use-Zeilen mit einem Namen). Die Regel ist dieselbe: ein Name, ein Ding, pro Modul. Wie use funktioniert, steht unter Module.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: Den Import mit as umbenennen
Abschnitt betitelt „Lösung 1: Den Import mit as umbenennen“Nimm diese Lösung, wenn du beide Typen in derselben Datei brauchst. Das ist häufig: dein eigenes Error für die Regeln deiner App und io::Error für Dateien und das Netzwerk. Gib dem Import einen Spitznamen, der sagt, woher er kommt. IoError liest sich besser als der Platzhalter OtherError von rustc:
use std::io::Error as IoError;use std::io::ErrorKind;
#[derive(Debug)]enum Error { EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } if name.len() > 10 { return Err(Error::TooLong(name.len())); } Ok(())}
fn save_name(name: &str) -> Result<(), IoError> { if name == "root" { return Err(IoError::new(ErrorKind::PermissionDenied, "dieser Name ist reserviert")); } Ok(())}
fn main() { println!("{:?}", check_name("Ferris")); println!("{:?}", check_name("")); println!("{:?}", check_name("Ferris the Crab")); match save_name("root") { Ok(()) => println!("gespeichert"), Err(e) => println!("E/A-Fehler: {}", e), }}Ausgabe:
Ok(())Err(EmptyName)Err(TooLong(15))E/A-Fehler: dieser Name ist reserviertDie Namen, die an check_name gehen, bleiben auf Englisch, weil die Funktion ihre Länge in Bytes zählt (name.len()), und Umlaute zählen dort doppelt.
as ändert den Namen nur in dieser Datei. Überall sonst heißt der Typ weiterhin std::io::Error.
Lösung 2: Das Modul importieren, nicht den Typ
Abschnitt betitelt „Lösung 2: Das Modul importieren, nicht den Typ“Nimm diese Lösung, wenn jedes Error bei jeder Verwendung zeigen soll, woher es kommt. Importiere das übergeordnete Modul mit use std::io; und schreib io::Error. Dein eigenes Error behält den kurzen Namen. Viele Rust-Entwickler bevorzugen diesen Stil bei Typen mit allgemeinen Namen wie Error und Result:
use std::io;
enum Error { EmptyName,}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } Ok(())}
fn save_name(name: &str) -> Result<(), io::Error> { if name == "root" { return Err(io::Error::new(io::ErrorKind::PermissionDenied, "reservierter Name")); } Ok(())}
fn main() { if let Err(Error::EmptyName) = check_name("") { println!("Name ist leer"); } if let Err(e) = save_name("root") { println!("E/A-Fehler: {}", e); }}Ausgabe:
Name ist leerE/A-Fehler: reservierter NameLösung 3: Dein eigenes Element umbenennen
Abschnitt betitelt „Lösung 3: Dein eigenes Element umbenennen“Nimm diese Lösung, wenn dein Typ in vielen Dateien oder von anderen Leuten benutzt wird. Ein genauer Name wie NameError oder AppError ist klarer als ein zweites Error, und die use-Zeile kann bleiben, wie sie ist:
use std::io::Error;
#[derive(Debug)]enum NameError { EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), NameError> { if name.is_empty() { return Err(NameError::EmptyName); } if name.len() > 10 { return Err(NameError::TooLong(name.len())); } Ok(())}
fn main() { println!("{:?}", check_name("Ferris the Crab")); let disk = Error::other("Festplatte ist voll"); println!("{}", disk);}Ausgabe:
Err(TooLong(15))Festplatte ist vollIn größeren Projekten macht das Crate thiserror solche Fehler-Enums viel kürzer. Siehe Eigene Fehlertypen.
Lösung 4: Den ungenutzten Import löschen
Abschnitt betitelt „Lösung 4: Den ungenutzten Import löschen“Nimm diese Lösung, wenn rustc zusätzlich warning: unused import ausgibt, wie in der Fehlermeldung oben. Der Import ist ein Überbleibsel von früherem Code oder wurde von deinem Editor eingefügt. Lösch die Zeile, und das Programm vom Anfang dieser Seite funktioniert so, wie es dasteht:
enum Error { EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } if name.len() > 10 { return Err(Error::TooLong(name.len())); } Ok(())}
fn main() { match check_name("") { Ok(()) => println!("Name ist in Ordnung"), Err(Error::EmptyName) => println!("Name ist leer"), Err(Error::TooLong(n)) => println!("Name hat {} Buchstaben, erlaubt sind höchstens 10", n), }}Ausgabe:
Name ist leerWo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“Eine eigene Funktion mit einem Namen aus der Standardbibliothek. use std::mem::swap; plus fn swap(a: &mut i32, b: &mut i32) ergibt E0255 mit „previous import of the value swap here“ und der Notiz „value namespace“. Lösung: Nenn deine Funktion swap_values, oder lass den Import weg, wenn du sowieso deine eigene schreiben wolltest.
Kopieren und Einfügen zwischen Modulen. Du verschiebst struct User nach mod models, ergänzt oben use models::User;, vergisst aber, das alte struct User in main.rs zu löschen. Lösung: Lösch die alte Kopie, damit User nur noch das Struct in models meint.
Ein Trait mit einem Namen aus der Standardbibliothek. use std::fmt::Display; und dein eigenes trait Display kollidieren genauso („previous import of the trait Display“). Lösung: Benenn deinen Trait um (Describe, Render), oder schreib use std::fmt; und fmt::Display.
Gut zu wissen: Ein Glob-Import wie use std::io::*; führt nie zu E0255. Deine eigenen Elemente gewinnen stillschweigend gegen Namen, die über ein * hereinkommen. Das ist praktisch, kann aber auch verstecken, welches Error du gerade benutzt. Ausdrückliche Imports sind deshalb meistens klarer.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0252: Zwei
use-Zeilen holen denselben Namen, etwafmt::Resultundio::Result. - E0428: Zwei deiner eigenen Elemente haben denselben Namen, oft weil du eine Funktion überladen wolltest.
- E0592: zwei Methoden mit demselben Namen in einem
impl-Block. - E0432: Die
use-Zeile selbst zeigt auf etwas, das es nicht gibt. - E0425: das umgekehrte Problem – ein Name, der dort, wo du ihn benutzt, gar nicht definiert ist.
- Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Deine Datei beginnt mit use std::fmt::Result; und definiert später enum Result { Pass, Fail }. Welchen Fehler bekommst du?
2. Du brauchst std::io::Error und dein eigenes enum Error in einer Datei. Was ist eine saubere Lösung?
3. rustc zeigt E0255 und zusätzlich warning: unused import: std::io::Error. Was sagt dir die Warnung?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0255 – Rust error codes index (auf Englisch): die offizielle Erklärung, mit einem
use bar::foo;, das mitfn fookollidiert, gelöst mitasoder dem Pfad des Elternmoduls. - Mit dem Schlüsselwort as neue Namen vergeben – Das Rust-Buch: wie
aseinen Import umbenennt, mit den zweiResult-Typen. - Use declarations – The Rust Reference (auf Englisch): jede Form von
use, auchas, Gruppen und Globs. - Namespaces – The Rust Reference (auf Englisch): der Typ- und der Werte-Namensraum aus der Notiz des Fehlers.
- The
usedeclaration – Rust by Example (auf Englisch): kurze, ausführbare Beispiele zum Importieren und Umbenennen.