Rust-Fehler E0603: function, struct or module is private (privates Element)
E0603 ist eigentlich eine gute Nachricht in Verkleidung: Rust hat die Funktion, das Struct oder das Modul, nach dem du gefragt hast, gefunden. Es darf sie dir nur nicht geben, weil das Element privat ist. In einem Rust-Modul ist alles privat, bis du etwas anderes sagst. Deshalb begegnet fast jedem dieser Fehler, sobald er seinen Code zum ersten Mal auf Module aufteilt. Die Lösung ist meistens ein einziges Wort: pub. Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0603]: function `apply_discount` is private --> src/main.rs:8:26 |8 | let total = billing::apply_discount(200); // ❌ privat | ^^^^^^^^^^^^^^ private function |note: the function `apply_discount` is defined here --> src/main.rs:2:5 |2 | fn apply_discount(price: u32) -> u32 { // kein `pub` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Auf Deutsch heißt das: „Die Funktion apply_discount ist privat.“ Die note: darunter sagt dir, wo sie definiert ist. Dieses Programm erzeugt die Meldung:
mod billing { fn apply_discount(price: u32) -> u32 { // kein `pub` price * 90 / 100 }}
fn main() { let total = billing::apply_discount(200); // ❌ privat println!("Total: {total}");}Die erste Zeile nennt die Art des Elements. Deshalb gibt es denselben Fehler in mehreren Varianten:
| Was in der ersten Zeile steht | Was meistens schiefgelaufen ist | Lösung |
|---|---|---|
function `apply_discount` is private |
Das fn hat kein pub |
Lösung 1 oder 2 |
struct `Order` is private |
Das struct hat kein pub |
Lösung 1 |
module `prices` is private |
Einem mod auf dem Pfad fehlt pub |
Lösung 1 oder 3 |
function import `price_of` is private |
Du greifst über ein einfaches use in einem anderen Modul auf das Element zu |
Lösung 3 |
tuple struct constructor `Percent` is private |
Das Struct ist pub, seine Felder aber nicht |
Lösung 4 |
Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Lies die beiden Pfeile. Der erste (Zeile 8) zeigt, wo du das Element benutzt. Der Pfeil bei note: (Zeile 2) zeigt, wo es definiert ist. Rust sagt also: „Ich sehe apply_discount dort drüben, aber es wurde nie zum Teilen freigegeben. Code außerhalb von billing darf es deshalb nicht aufrufen.“
Die Datei spielt dabei keine Rolle. Liegt billing in src/billing.rs, bekommst du denselben Fehler, und die note: zeigt einfach auf src/billing.rs:1:1.
Stell dir ein Bürogebäude vor. Jedes Modul ist ein Raum mit einer Tür. Ein privates Element ist ein Werkzeug, das in seinem Raum bleibt: Wer im Raum ist (oder in kleineren Räumen darin), darf es benutzen, aber niemand vom Flur aus. pub legt das Werkzeug in ein Regal auf dem Flur.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“In Rust ist alles standardmäßig privat: Funktionen, Structs, Felder von Structs, Module und sogar use-Importe. Teilen musst du ausdrücklich mit pub erlauben. Die Lektion Module zeigt das von Anfang an.
Der Grund ist Sicherheit für dein zukünftiges Ich. Alles, was pub ist, wird zu einem Versprechen: Anderer Code darf sich darauf verlassen, und wenn du es änderst, kann dieser Code kaputtgehen. Private Elemente kannst du frei ändern, umbenennen oder löschen, und der Compiler garantiert, dass sich niemand von außen darauf verlässt. Kleine Hilfsfunktionen bleiben Hilfsfunktionen. Und ein Struct kann seine eigenen Regeln schützen (etwa „ein Kontostand ist nie negativ“), weil niemand sonst direkt an seine Felder kommt.
Noch ein Detail: Die Sichtbarkeit wird für jeden Schritt eines Pfads geprüft. shop::prices::price_of funktioniert nur, wenn prices für dich sichtbar ist und price_of für dich sichtbar ist. Ein pub fn in einem privaten Modul bleibt trotzdem außer Reichweite.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: pub an das Element schreiben (und an jedes Modul auf dem Pfad)
Abschnitt betitelt „Lösung 1: pub an das Element schreiben (und an jedes Modul auf dem Pfad)“Nimm diese Lösung, wenn das Element von außerhalb seines Moduls benutzt werden soll. Meistens ist das die richtige Lösung:
mod billing { pub fn apply_discount(price: u32) -> u32 { price * 90 / 100 }}
fn main() { let total = billing::apply_discount(200); println!("Summe: {total}");}Ausgabe:
Summe: 180Sagt der Fehler module `prices` is private, fehlt das pub am Modul: Schreib pub mod prices { ... }. rustc weist dich auf diesen Fall auch mit einer zweiten Beschriftung hin: function `price_of` is not publicly re-exported (price_of wird nicht öffentlich weitergegeben). Bei einer eigenen Datei kommt das pub an die Deklarationszeile: pub mod prices;.
Bei einem Struct macht pub struct Order den Typ öffentlich. Jedes Feld braucht aber trotzdem sein eigenes pub, wenn Code von außen es lesen oder setzen soll. Mehr dazu in Lösung 4.
Lösung 2: pub(crate) oder pub(super) für „nur mein eigener Code“
Abschnitt betitelt „Lösung 2: pub(crate) oder pub(super) für „nur mein eigener Code““Nimm diese Lösung, wenn das Element geteilt werden soll, aber nicht mit der ganzen Welt. pub gibt es in mehreren Stufen, von der kleinsten bis zur größten:
| Du schreibst | Wer das Element benutzen darf |
|---|---|
| nichts (privat) | sein eigenes Modul und die Module darin |
pub(super) |
zusätzlich das übergeordnete Modul |
pub(crate) |
jeder Code in diesem Crate |
pub |
alle, auch andere Crates, die von deinem abhängen |
In einem Programm (einem Binary) verhalten sich pub(crate) und pub fast gleich. Der Unterschied zählt in einer Bibliothek: Mit pub(crate) können deine Module eine Hilfsfunktion teilen, ohne dass sie Teil der öffentlichen API der Bibliothek wird.
mod shop { // Jeder Code in diesem Crate darf das aufrufen. pub(crate) fn store_name() -> &'static str { "Ferris Fruits" }
pub mod receipt { // Nur das übergeordnete Modul, `shop`, darf diese Hilfsfunktion aufrufen. pub(super) fn line(item: &str, price: u32) -> String { format!("{item}: {price}") } }
pub fn print_receipt(items: &[(&str, u32)]) { println!("== {} ==", store_name()); for (item, price) in items { println!("{}", receipt::line(item, *price)); } }}
fn main() { println!("Willkommen bei {}", shop::store_name()); shop::print_receipt(&[("Apfel", 3), ("Birne", 5)]); // shop::receipt::line("Apfel", 3); // ❌ E0603: `line` ist nur für `shop`}Ausgabe:
Willkommen bei Ferris Fruits== Ferris Fruits ==Apfel: 3Birne: 5Entferne die // vor der letzten Zeile, und du bekommst function `line` is private, obwohl dort pub(super) steht. main ist nicht das übergeordnete Modul von receipt, also bleibt die Tür zu.
Lösung 3: Mit pub use weiterreichen
Abschnitt betitelt „Lösung 3: Mit pub use weiterreichen“Nimm diese Lösung, wenn das innere Modul ein internes Detail ist, aber ein Element darin leicht erreichbar sein soll. Lass das Modul privat und stell das Element unter einen kürzeren, öffentlichen Pfad:
mod shop { mod prices { // bleibt privat: wie Preise gespeichert werden, ist Sache von shop pub fn price_of(item: &str) -> u32 { if item == "Apfel" { 3 } else { 5 } } }
pub use prices::price_of; // jetzt erreichbar als shop::price_of}
fn main() { println!("Äpfel kosten {}", shop::price_of("Apfel")); println!("Birnen kosten {}", shop::price_of("Birne"));}Ausgabe:
Äpfel kosten 3Birnen kosten 5Das ist auch die Lösung für function import `price_of` is private (der Funktionsimport price_of ist privat). Ein einfaches use prices::price_of; in shop ist eine Abkürzung nur für shop. Wie alles andere ist auch ein use privat. pub use macht aus der Abkürzung eine öffentliche Tür. Große Crates machen das ständig. Deshalb kannst du serde::Serialize schreiben, ohne zu wissen, in welchem inneren Modul es liegt.
Lösung 4: Ein pub fn new ergänzen, statt die Felder öffentlich zu machen
Abschnitt betitelt „Lösung 4: Ein pub fn new ergänzen, statt die Felder öffentlich zu machen“Nimm diese Lösung, wenn es im Fehler um die Felder eines Structs oder um seinen Konstruktor geht. Hier ist das Struct pub, sein Feld aber nicht:
mod billing { pub struct Percent(u8);}
fn main() { let discount = billing::Percent(150); // ❌ privater Konstruktor}error[E0603]: tuple struct constructor `Percent` is private --> src/main.rs:6:29 |2 | pub struct Percent(u8); | -- a constructor is private if any of the fields is private...6 | let discount = billing::Percent(150); // ❌ privater Konstruktor | ^^^^^^^ private tuple struct constructor |help: consider making the field publicly accessible |2 | pub struct Percent(pub u8); | +++Rust erklärt: Ein Konstruktor ist privat, sobald eines der Felder privat ist. rustc schlägt pub u8 vor, und für einen reinen Datentyp ist das in Ordnung. Aber sieh dir den Wert an: 150 Prozent! Oft ist das private Feld genau der Sinn der Sache. Das Modul will den Wert prüfen, bevor ein Percent entsteht. Gib ihm einen öffentlichen Konstruktor, der die Prüfung übernimmt:
mod billing { pub struct Percent(u8);
impl Percent { pub fn new(value: u8) -> Option<Percent> { if value <= 100 { Some(Percent(value)) } else { None } }
pub fn apply(&self, price: u32) -> u32 { price * (100 - self.0 as u32) / 100 } }}
fn main() { let ten = billing::Percent::new(10).unwrap(); println!("200 mit 10 % Rabatt: {}", ten.apply(200)); println!("Sind 150 % erlaubt? {}", billing::Percent::new(150).is_some());}Ausgabe:
200 mit 10 % Rabatt: 180Sind 150 % erlaubt? falseJetzt liegt garantiert jedes Percent im ganzen Programm zwischen 0 und 100, und apply kann nie unterlaufen. Denk daran, dass auch new selbst pub braucht. Eine private Methode ergibt einen anderen Fehler, E0624 (associated function `new` is private, die assoziierte Funktion new ist privat). Mehr über Konstruktoren findest du unter Structs.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“Ein Paket mit main.rs und lib.rs. Das sind zwei getrennte Crates, und main.rs benutzt die Bibliothek von außen. Steht in lib.rs nur mod inventory;, schlägt use shop::inventory::count_items; in main.rs fehl:
error[E0603]: module `inventory` is private --> src/main.rs:1:11 |1 | use shop::inventory::count_items; | ^^^^^^^^^ private moduleDas Modul inventory ist privat. Lösung: Schreib pub mod inventory; in lib.rs und pub fn count_items in das Modul. Vorsicht: pub(crate) reicht hier nicht. Für die Bibliothek ist main.rs ein anderes Crate, also ergibt ein pub(crate) fn trotzdem function `count_items` is private. Siehe Cargo und Crates.
Private Felder eines Structs. Dafür gibt es eigene Fehlercodes. Ein Struct mit privatem Feld zu erstellen ergibt E0451, so ein Feld zu lesen ergibt E0616:
error[E0451]: field `balance` of struct `Account` is privateerror[E0616]: field `balance` of struct `Account` is privateBeide sagen: Das Feld balance des Structs Account ist privat. Lösung: dieselbe Wahl wie in Lösung 4. Schreib pub an das Feld, wenn es jeder ändern darf, oder lass es privat und ergänze pub fn new(...) plus einen Getter wie pub fn balance(&self) -> u64.
Eine Funktion, die du im Quellcode eines Crates gefunden hast. Du liest ein Crate auf GitHub, findest die perfekte Hilfsfunktion und bekommst E0603, wenn du sie aufrufst. Haben die Autoren des Crates sie nicht pub gemacht, kannst du sie nicht benutzen – und sie dürfen sie jederzeit ändern. Such auf der Seite des Crates bei docs.rs nach einem öffentlichen Weg, dasselbe zu erreichen. Dort erscheinen nur pub-Elemente.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0432:
unresolved import. Das Element wurde gar nicht gefunden. Bei E0603 wurde es gefunden, ist aber privat. - E0433:
failed to resolve, ein Pfad in deinem Code, der ins Leere führt. - E0451 und E0616: Ein Feld eines Structs ist privat (beim Erstellen des Structs oder beim Lesen des Felds).
- E0624: Eine Methode oder assoziierte Funktion (wie
new) ist privat. - Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. mod shop { mod prices { pub fn price_of() {} } }, und main ruft shop::prices::price_of() auf. Welchen Fehler bekommst du?
2. Eine Hilfsfunktion in src/lib.rs ist mit pub(crate) markiert. Kann src/main.rs im selben Paket sie aufrufen?
3. Ein pub struct Email(String); hält sein Feld absichtlich privat. Wie lässt du andere Module freundlich eins erstellen?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0603 – Rust error codes index (auf Englisch): die offizielle Erklärung mit einem minimalen Beispiel.
- Mit Pfaden auf ein Element im Modulbaum verweisen – Das Rust-Buch: Pfade mit
puböffentlich machen und wiepubbei Structs und Enums wirkt. - Pfade in den Gültigkeitsbereich bringen mit dem Schlüsselwort use – Das Rust-Buch: Namen mit
pub useweiterreichen (Re-Export). - Visibility – Rust by Example (auf Englisch):
pub,pub(crate),pub(super)undpub(in path)in einem ausführbaren Beispiel. - Visibility and privacy – The Rust Reference (auf Englisch): die genauen Regeln, wenn du das ganze Bild willst.