Zum Inhalt springen

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.)

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);
}

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.

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.

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"),
email: String::from("[email protected]"), // ✅ ergänzt
active: true,
};
println!("{} <{}> aktiv: {}", user.name, user.email, user.active);
}

Ausgabe:

Ferris <[email protected]> aktiv: true
▶ Selbst ausprobieren

Lö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 }
▶ Selbst ausprobieren

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)]).

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 1
Bo: Punkte 50, Level 1
▶ Selbst ausprobieren

Auch 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 }
▶ Selbst ausprobieren

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.

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"),
email: String::from("[email protected]"),
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: None
▶ Selbst ausprobieren

Achte 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.

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.

  • 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 leitet Default nicht 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 Account with struct literal syntax due to private fields“ (wegen privater Felder lässt sich Account nicht per Struct-Literal erzeugen). So oder so: Benutze die Funktion new des Moduls.
  • E0382: use of moved value: Du hast einen Wert benutzt, nachdem ..value seine Felder herausverschoben hat.
  • Alle Compilerfehler einfach erklärt

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