Rust-Fehler E0616: field of struct is private (privates Feld)
E0616 bedeutet: Das Feld, nach dem du fragst, existiert – aber es ist privat in dem Modul, in dem das Struct definiert ist. Das Struct selbst darfst du benutzen, nur nicht hineingreifen. Der Fehler passiert jedem, der ein Struct zum ersten Mal in ein eigenes Modul verschiebt. Und jedem, der v.len statt v.len() tippt. Die Lösung ist meistens ein Methodenaufruf. Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0616]: field `balance` of struct `Account` is private --> src/main.rs:16:50 |16 | println!("{} has {}", account.owner, account.balance); // ❌ privates Feld | ^^^^^^^ private fieldAuf Deutsch heißt das: „Das Feld balance des Structs Account ist privat.“ Dieses Programm erzeugt die Meldung:
mod bank { pub struct Account { pub owner: String, balance: u64, // privat }
impl Account { pub fn new(owner: &str) -> Account { Account { owner: owner.to_string(), balance: 0 } } }}
fn main() { let account = bank::Account::new("Ferris"); println!("{} has {}", account.owner, account.balance); // ❌ privates Feld}Denselben Fehler gibt es in mehreren Varianten:
| Was du geschrieben hast | Was rustc sagt | Lösung |
|---|---|---|
account.balance |
field `balance` of struct `Account` is private |
Lösung 2 oder 3 |
scores.len bei einem Vec |
field `len` of struct `Vec` is private, dazu help: a method `len` also exists, call it with parentheses |
Lösung 1 |
timeout.secs bei einer Duration |
field `secs` of struct `Duration` is private |
Lösung 1 (as_secs()) |
account.balance = 500 |
dasselbe E0616: Auch Schreiben ist verboten | Lösung 2 |
Das help in der zweiten Zeile heißt: „Es gibt auch eine Methode len, ruf sie mit Klammern auf.“
Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Der Pfeil zeigt auf den Feldnamen nach dem Punkt. account.owner in derselben Zeile ist in Ordnung, weil owner mit pub markiert ist. balance ist es nicht. Deshalb darf nur Code innerhalb von mod bank das Feld lesen oder ändern.
Beachte, dass Account selbst pub ist. Genau das überrascht viele: Ein öffentliches Struct macht seine Felder nicht öffentlich. Jedes Feld bekommt sein eigenes pub – oder bleibt privat.
Stell dir eine Bank vor. Du darfst hineingehen, und jeder kann den Namen auf deinem Konto sehen. Aber du darfst nicht hinter den Schalter gehen und den Tresor öffnen, um das Geld zu zählen. Du fragst am Schalter nach, und dort hält man sich an die Regeln der Bank.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“In Rust ist alles standardmäßig privat: Funktionen, Module und eben auch die Felder von Structs (siehe Module). Die Sichtbarkeit hängt am Modul, nicht am Typ. Jeder Code innerhalb von mod bank darf balance anfassen, Code von außerhalb nicht.
Der Sinn: Ein Struct kann seine eigenen Regeln schützen. Sagen wir, ein Kontostand darf nie negativ werden. Könnte jeder Teil des Programms account.balance = ... schreiben, könnte jeder Teil diese Regel brechen. Dann müsstest du die ganze Codebasis durchsuchen, um den Schuldigen zu finden. Ist das Feld privat, können es nur die paar Methoden in mod bank ändern. Prüfst du die Regel dort, gilt sie überall. Diese Idee heißt Kapselung (Encapsulation).
Die Standardbibliothek macht es genauso. Ein Vec hat private Felder für seine Länge und seinen Speicherpuffer. Könntest du bei einem Vektor mit 3 Elementen v.len = 100 schreiben, würde v[50] irgendeinen zufälligen Speicher lesen. Dass len privat bleibt, macht Vec erst sicher.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: Die Methode aufrufen, statt das Feld zu lesen
Abschnitt betitelt „Lösung 1: Die Methode aufrufen, statt das Feld zu lesen“Nimm diese Lösung, wenn das Struct aus der Standardbibliothek oder einem anderen Crate kommt. Deren Code kannst du nicht ändern, und sie geben dir immer Methoden für alles, was du sehen darfst. Wenn rustc help: a method ... also exists sagt, ergänze die ():
use std::time::Duration;
fn main() { let scores = vec![10, 20, 30]; println!("{} Ergebnisse", scores.len());
let timeout = Duration::from_secs(90); println!("Timeout: {} Sekunden", timeout.as_secs());}Ausgabe:
3 ErgebnisseTimeout: 90 SekundenDie Methode heißt nicht immer wie das Feld (secs liest du mit as_secs()). Schau auf der Seite des Typs bei docs.rs nach, oder lass dir von deinem Editor nach dem Punkt die Methoden anzeigen.
Lösung 2: Einen Getter ergänzen – und Methoden, die die Regeln einhalten
Abschnitt betitelt „Lösung 2: Einen Getter ergänzen – und Methoden, die die Regeln einhalten“Nimm diese Lösung, wenn es dein eigenes Struct ist und das Feld eine Regel schützen soll. Lass das Feld privat und ergänze eine pub fn, die seinen Wert zurückgibt (einen Getter). Ändern darf man das Feld nur über Methoden, die die Regel prüfen:
mod bank { pub struct Account { pub owner: String, balance: i64, // privat: nur dieses Modul darf es ändern }
impl Account { pub fn new(owner: &str) -> Account { Account { owner: owner.to_string(), balance: 0 } }
// Getter: Jeder darf den Kontostand lesen. pub fn balance(&self) -> i64 { self.balance }
pub fn deposit(&mut self, amount: i64) { if amount > 0 { self.balance += amount; } }
// Hier wohnt die Regel: Der Kontostand fällt nie unter null. pub fn withdraw(&mut self, amount: i64) -> Result<(), String> { if amount > self.balance { return Err(format!("nur {} verfügbar", self.balance)); } self.balance -= amount; Ok(()) } }}
fn main() { let mut account = bank::Account::new("Ferris"); account.deposit(100); println!("{} hat {}", account.owner, account.balance());
match account.withdraw(500) { Ok(()) => println!("500 abgehoben"), Err(e) => println!("500 abheben geht nicht: {e}"), } println!("Kontostand ist weiterhin {}", account.balance());}Ausgabe:
Ferris hat 100500 abheben geht nicht: nur 100 verfügbarKontostand ist weiterhin 100In Rust dürfen eine Methode und ein Feld denselben Namen haben. Deshalb heißt der Getter üblicherweise balance() (nicht get_balance()). Sobald es den Getter gibt, schlägt rustc ihn sogar selbst vor: help: a method `balance` also exists, call it with parentheses. deposit und withdraw sind deine Setter: Sie ändern das Feld, aber nur so, wie die Regeln es erlauben. Mehr über Methoden findest du unter Structs.
Lösung 3: Das Feld pub machen, wenn es einfache Daten sind
Abschnitt betitelt „Lösung 3: Das Feld pub machen, wenn es einfache Daten sind“Nimm diese Lösung, wenn jeder Wert in Ordnung ist und nichts anderes von dem Feld abhängt. Ein Punkt auf einem Raster, eine Farbe oder ein Struct mit Einstellungen hat keine Regel zu schützen. Getter wären hier nur zusätzliche Tipparbeit:
mod geometry { pub struct Point { pub x: i32, pub y: i32, }}
fn main() { let mut p = geometry::Point { x: 3, y: 4 }; p.x += 1; println!("Punkt bei ({}, {})", p.x, p.y);}Ausgabe:
Punkt bei (4, 4)Soll nur dein eigener Code das Feld sehen, schreib pub(crate) x: i32 (jedes Modul in diesem Crate) oder pub(super) x: i32 (nur das übergeordnete Modul). In einem Programm verhalten sie sich wie pub. In einer Library halten sie das Feld aus deiner öffentlichen API heraus. Auf der Seite zu E0603 findest du eine Tabelle mit allen Stufen.
Soll ich es einfach pub machen? Frag dich: „Kann ein bestimmter Wert dieses Felds – oder eine Änderung nur an diesem Feld – das Struct ungültig machen?“ Ein negativer Kontostand, ein len, das nicht zu den Daten passt, ein total, das nicht mehr der Summe der Posten entspricht: Solche Felder bleiben privat, und du nimmst Lösung 2. Lautet die Antwort „Nein, jeder Wert ist in Ordnung“, ist pub die ehrliche Wahl.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“len bei einem Vec. Du hast scores.len geschrieben und field `len` of struct `Vec` is private bekommen. Das liegt daran, dass Vec tatsächlich ein privates Feld namens len hat. Die Lösung ist scores.len(). Lustiges Detail: name.len bei einem String liefert einen anderen Fehler, E0615 (attempted to take value of method, „Versuch, den Wert einer Methode zu nehmen“), weil String kein Feld mit diesem Namen hat. Die Lösung ist dieselbe.
Ein Feld von außen setzen. account.balance = 500; liefert dasselbe E0616. Auch Schreiben ist verboten. Mach das Feld nicht nur deshalb pub, um es setzen zu können. Ergänze lieber eine Methode wie deposit, die die Änderung vornimmt und prüft.
Nachdem du ein Struct in ein eigenes Modul oder eine eigene Datei verschoben hast. Der Code in main.rs hat monatelang user.email benutzt. Dann hast du User nach src/user.rs verschoben, und jeder Feldzugriff ist kaputt. Felder, die vorher in Ordnung waren, sind jetzt privat in mod user. Gib den Feldern mit einfachen Daten ein pub und den übrigen Getter.
Tests. Ein #[cfg(test)] mod tests-Block in derselben Datei ist ein Kind-Modul und darf deshalb private Felder lesen. Tests im Ordner tests/ liegen außerhalb deines Crates. Sie können, wie jeder andere Benutzer, nur die pub-API benutzen.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0603:
function `x` is private. Dieselbe Idee für Funktionen, Structs und Module. - E0451: dasselbe private Feld, aber beim Erzeugen des Structs mit
Account { ... }. - E0624:
method `x` is private. Auch die Methode (odernew) brauchtpub. - E0609:
no field `x` on type `T`. Das Feld gibt es überhaupt nicht (oft ein Tippfehler). - E0615:
attempted to take value of method. Du hastx.lengeschrieben undx.len()gemeint. - Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. pub struct Account { balance: u64 } steht in mod bank. Darf main account.balance lesen?
2. Du bekommst `field len of struct Vec is private`. Wie behebst du das?
3. Ein Struct Score hat ein Feld points, das zwischen 0 und 100 bleiben muss. Was ist das beste Design?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0616 – Rust error codes index (auf Englisch): die offizielle Erklärung mit einem minimalen Beispiel.
- Strukturen und Aufzählungen öffentlich machen – Das Rust-Buch: warum ein
pub structtrotzdem private Felder hat, an einem Restaurant-Beispiel. - Kapselung, die Implementierungsdetails verbirgt – Das Rust-Buch: ein Struct, das seinen Durchschnitt korrekt hält, weil seine Felder privat sind.
- Struct visibility – Rust by Example (auf Englisch): öffentliche und private Felder nebeneinander, in einem ausführbaren Beispiel.
- Structs have private fields (C-STRUCT-PRIVATE) – Rust API Guidelines (auf Englisch): warum Libraries ihre Felder privat halten, damit sie sie später ändern können.