Rust-Fehler E0063: missing field in initializer (fehlendes Feld)
E0063 bedeutet: Du erzeugst ein Struct mit Name { ... }, hast aber nicht jedem Feld einen Wert gegeben. Rust füllt nie Felder für dich aus. Jedes Feld braucht also einen Wert, und sei es nur 0, false oder None. Die Meldung nennt die fehlenden Felder beim Namen, du weißt also genau, was du ergänzen musst. Das ist einer der freundlichsten Fehler in Rust. (Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.)
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0063]: missing field `email` in initializer of `User` --> src/main.rs:8:16 |8 | let user = User { | ^^^^ missing `email`Auf Deutsch: „Feld email fehlt beim Erzeugen von User.“ Die Markierung sagt nur: „email fehlt“.
Dieses Programm erzeugt den Fehler:
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { name: String::from("Ferris"), active: true, // ❌ kein `email` }; println!("{}", user.name);}Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Die Überschrift nennt das fehlende Feld (email) und das Struct (User). Die ^^^^ zeigen auf den Namen des Structs, wo du angefangen hast, es zu bauen, und nicht auf eine einzelne Zeile. Das Problem ist ja etwas, das nicht da ist.
Fehlen mehrere Felder, listet rustc sie in alphabetischer Reihenfolge auf. Bei zwei oder drei siehst du alle:
error[E0063]: missing fields `debug`, `retries` and `timeout_secs` in initializer of `Config`Ab vier zeigt rustc drei an und zählt den Rest:
error[E0063]: missing fields `debug`, `port`, `retries` and 1 other field in initializer of `Config` --> src/main.rs:10:18 |10 | let config = Config { | ^^^^^^ missing `debug`, `port`, `retries` and 1 other field„1 other field“ heißt: Es fehlt noch ein weiteres Feld. Schau in die Definition von struct Config, um die ganze Liste zu sehen.
Das ist wie ein Formular, bei dem jedes Kästchen ein Pflichtfeld ist. Du kannst es nicht abgeben, wenn das Kästchen „E-Mail“ leer ist – auch nicht, wenn du es später ausfüllen wolltest.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“In vielen Sprachen wird ein fehlendes Feld stillschweigend zu null, 0 oder einer leeren Zeichenkette. Dann läuft dein Programm mit einem Benutzer ohne E-Mail-Adresse und geht irgendwo ganz anders kaputt, oft erst in Produktion. Rust hat kein null und erfindet keine Werte hinter deinem Rücken. Ein User hat immer eine echte email. Siehe Ein Struct definieren und erstellen.
Das heißt nicht, dass du jedes Mal jedes Feld tippen musst. Rust bietet dir kurze Wege, um „nimm die Standardwerte“ oder „übernimm den Rest von diesem anderen Wert“ zu sagen. Die Lösungen unten zeigen sie. Wichtig ist: Du entscheidest, und die Entscheidung steht im Code.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: Das fehlende Feld ergänzen
Abschnitt betitelt „Lösung 1: Das fehlende Feld ergänzen“Nimm diese Lösung in den meisten Fällen. Das Feld gibt es aus gutem Grund, also gib ihm einen echten Wert. Hast du eine Variable mit demselben Namen wie das Feld, kannst du die Kurzschreibweise User { name, email, active } benutzen.
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { name: String::from("Ferris"), active: true, }; println!("{} <{}> aktiv: {}", user.name, user.email, user.active);}Ausgabe:
Ferris <[email protected]> aktiv: trueLösung 2: Default ableiten und ..Default::default() benutzen
Abschnitt betitelt „Lösung 2: Default ableiten und ..Default::default() benutzen“Nimm diese Lösung, wenn das Struct viele Felder hat und die meisten einen naheliegenden „leeren“ Wert haben, etwa bei Einstellungen oder Optionen. Schreib #[derive(Default)] über das Struct. Dann gibst du nur die Felder an, die dich interessieren, und schließt mit ..Default::default() ab. Das .. bedeutet: „Nimm jedes Feld, das ich nicht geschrieben habe, aus diesem Wert.“
#[derive(Debug, Default)]struct Config { host: String, port: u16, debug: bool, timeout_secs: u64, retries: u8,}
fn main() { let config = Config { host: String::from("localhost"), port: 8080, ..Default::default() // ✅ debug, timeout_secs und retries bekommen Standardwerte }; println!("{:?}", config);}Ausgabe:
Config { host: "localhost", port: 8080, debug: false, timeout_secs: 0, retries: 0 }Die abgeleiteten Standardwerte sind 0 für Zahlen, false für bool, ein leerer String und None für eine Option. Ist 0 ein schlechter Standardwert (ein Timeout von 0 Sekunden ist es vermutlich), schreib impl Default for Config selbst, mit besseren Werten. Siehe Default: ein sinnvoller Startwert.
Vergisst du das #[derive(Default)], wird daraus E0277: the trait bound `Config: Default` is not satisfied (Config implementiert Default nicht), mit help: consider annotating `Config` with `#[derive(Default)]` (versieh Config mit #[derive(Default)]).
Lösung 3: Einen Konstruktor new schreiben
Abschnitt betitelt „Lösung 3: Einen Konstruktor new schreiben“Nimm diese Lösung, wenn du das Struct an vielen Stellen erzeugst oder wenn manche Felder immer gleich anfangen. Schreib das vollständige Struct-Literal in eine einzige Funktion und ruf überall sonst diese Funktion auf. Kommt später ein Feld dazu, änderst du nur new und nicht jede Aufrufstelle.
struct Player { name: String, score: u32, level: u8,}
impl Player { fn new(name: &str) -> Player { Player { name: name.to_string(), score: 0, // jeder neue Spieler startet mit 0 ... level: 1, // ... auf Level 1 } }}
fn main() { let ana = Player::new("Ana"); let mut bo = Player::new("Bo"); bo.score += 50; println!("{}: Punkte {}, Level {}", ana.name, ana.score, ana.level); println!("{}: Punkte {}, Level {}", bo.name, bo.score, bo.level);}Ausgabe:
Ana: Punkte 0, Level 1Bo: Punkte 50, Level 1Auch das Struct-Literal in new braucht jedes Feld. Ein vergessenes Feld zeigt sich also dort als E0063. Das ist in Ordnung: Du behebst es nur einmal. Siehe Funktionen im Stil eines Konstruktors.
Lösung 4: Den Rest mit ..other von einem anderen Wert übernehmen
Abschnitt betitelt „Lösung 4: Den Rest mit ..other von einem anderen Wert übernehmen“Nimm diese Lösung, wenn du schon einen ähnlichen Wert hast und eine Kopie mit ein paar Änderungen willst. ..base übernimmt jedes Feld, das du nicht geschrieben hast, aus base:
#[derive(Debug, Clone)]struct Theme { name: String, font_size: u8, dark: bool,}
fn main() { let base = Theme { name: String::from("Standard"), font_size: 14, dark: false };
// nur `name` und `dark` ändern sich, der Rest kommt aus `base` let night = Theme { name: String::from("Nacht"), dark: true, ..base };
// `..base` würde `name` aus base verschieben, also klonen, damit base benutzbar bleibt let large = Theme { font_size: 20, ..base.clone() };
println!("{:?}", night); println!("{:?}", large); println!("{:?}", base);}Ausgabe:
Theme { name: "Nacht", font_size: 14, dark: true }Theme { name: "Standard", font_size: 20, dark: false }Theme { name: "Standard", font_size: 14, dark: false }Eins solltest du wissen: ..base verschiebt (moved) Felder wie String aus base heraus. Bei night ist das kein Problem, denn wir haben einen eigenen name geschrieben. Aus base kamen also nur die Copy-Felder (font_size). Bei large käme name aus base, deshalb benutzen wir ..base.clone(), damit base benutzbar bleibt. Lässt du das Klonen weg und benutzt base danach noch, bekommst du E0382.
Wenn Option-Felder helfen
Abschnitt betitelt „Wenn Option-Felder helfen“Manchmal darf ein Feld wirklich leer sein: eine Telefonnummer, die ein Benutzer noch nicht angegeben hat, ein Spitzname, ein Enddatum. Mach dieses Feld zu einer Option. Schreiben musst du es trotzdem (Rust füllt kein None für dich ein), aber None ist jetzt ein ehrlicher, erlaubter Wert. Siehe Option.
#[derive(Debug, Default)]struct Contact { name: String, email: String, phone: Option<String>, // darf fehlen nickname: Option<String>,}
fn main() { let a = Contact { name: String::from("Ana"), phone: None, // ausgeschrieben: „noch keine Telefonnummer“ nickname: Some(String::from("Annie")), }; // mit Default wird jede weggelassene Option zu None let b = Contact { name: String::from("Bo"), ..Default::default() };
println!("{} Telefon: {:?}, Spitzname: {:?}", a.name, a.phone, a.nickname); println!("{} E-Mail: {:?}, Telefon: {:?}", b.name, b.email, b.phone);}Ausgabe:
Ana Telefon: None, Spitzname: Some("Annie")Bo E-Mail: "", Telefon: NoneAchte darauf, dass b.email gleich "" ist. Das ist die Falle bei Default: Ein Pflichtfeld wird stillschweigend leer. Benutze Option nur für Dinge, die wirklich optional sind. Pflichtfelder wie email behalten einen normalen Typ, und du füllst sie immer aus.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“Direkt nachdem du einem Struct ein Feld hinzugefügt hast. Du ergänzt created_at in User, und plötzlich ergibt jedes User { ... } im Projekt E0063. Damit hilft dir Rust: Jede dieser Stellen solltest du dir ansehen. Ein Konstruktor new (Lösung 3) hält diese Liste kurz.
Enum-Varianten mit benannten Feldern. Shape::Rectangle { width: 2.0 } ergibt missing field `height` in initializer of `Shape`. Beachte, dass die Meldung das Enum nennt, nicht die Variante. Lösung: Gib jedem Feld dieser Variante einen Wert. Siehe Enums können Daten enthalten.
Eine Funktion, die ein Struct zurückgibt. In fn new_player(name: &str) -> Player { Player { name: name.to_string(), score: 0 } } zeigt der Pfeil auf Player in der Funktion, mit missing `level`. Lösung: Ergänze level in diesem Literal.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0560: struct has no field named x: das Gegenteil – ein Feld, das du geschrieben hast, das es im Struct aber nicht gibt. Ein Tippfehler ergibt oft beide auf einmal.
- E0559: variant has no field named x: derselbe Fehler mit dem falschen Namen, bei Enum-Varianten.
- E0277: trait bound not satisfied: Du hast
..Default::default()geschrieben, aber das Struct leitetDefaultnicht ab. - E0451: field is private: Das Struct kommt aus einem anderen Modul, und manche Felder sind privat, also kannst du sie nicht ausfüllen. Lässt du ein privates Feld weg, bekommst du nicht E0063, sondern „cannot construct
Accountwith struct literal syntax due to private fields“ (wegen privater Felder lässt sichAccountnicht per Struct-Literal erzeugen). So oder so: Benutze die Funktionnewdes Moduls. - E0382: use of moved value: Du hast einen Wert benutzt, nachdem
..valueseine Felder herausverschoben hat. - Alle Compilerfehler einfach erklärt
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. rustc sagt: missing fields a, b, c and 2 other fields. Wie viele Felder fehlen?
2. Dein Struct hat ein Feld Option<String>, das du noch nicht brauchst. Was schreibst du dafür?
3. Was braucht Config { port: 80, ..Default::default() }, damit es kompiliert?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0063 – Rust error codes index (auf Englisch): die offizielle Erklärung dieses Fehlers.
- Strukturen definieren und instanziieren – Das Rust-Buch: Struct-Literale, die Kurzschreibweise für Felder und die Update-Syntax für Structs.
Default– Doku der Standardbibliothek (auf Englisch):#[derive(Default)], ein eigenesimpl Defaultund..Default::default().- Struct expressions – The Rust Reference (auf Englisch): die genauen Regeln für
Name { field: value }und..base. - Constructors – Rust API Guidelines (auf Englisch): warum Rust-Code Funktionen namens
newbenutzt, um Structs zu bauen.