Erreur Rust E0603 : function, struct or module is private (élément privé)
E0603, c’est une bonne nouvelle déguisée : Rust a trouvé la fonction, la struct ou le module que vous demandiez. Il n’a simplement pas le droit de vous le donner, parce que l’élément est privé. En Rust, tout ce qui se trouve dans un module est privé tant que vous ne dites pas le contraire, alors presque tout le monde rencontre cette erreur la première fois qu’il découpe son code en modules. La correction tient en général en un mot : pub. Cette page fait partie du guide des erreurs du compilateur Rust.
Le message d’erreur
Section intitulée « Le message d’erreur »error[E0603]: function `apply_discount` is private --> src/main.rs:8:26 |8 | let total = billing::apply_discount(200); // ❌ privée | ^^^^^^^^^^^^^^ private function |note: the function `apply_discount` is defined here --> src/main.rs:2:5 |2 | fn apply_discount(price: u32) -> u32 { // pas de `pub` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Le compilateur vous dit : « la fonction apply_discount est privée ». La note indique où elle est définie.
Voici le programme qui la provoque :
mod billing { fn apply_discount(price: u32) -> u32 { // pas de `pub` price * 90 / 100 }}
fn main() { let total = billing::apply_discount(200); // ❌ privée println!("Total: {total}");}La première ligne nomme le genre d’élément, donc la même erreur existe en plusieurs variantes :
| Ce que dit la première ligne | Ce qui s’est généralement passé | Solution |
|---|---|---|
function `apply_discount` is private |
le fn n’a pas de pub |
Solution 1 ou 2 |
struct `Order` is private |
la struct n’a pas de pub |
Solution 1 |
module `prices` is private |
un mod sur le chemin n’a pas de pub |
Solution 1 ou 3 |
function import `price_of` is private |
vous avez atteint un élément via un simple use dans un autre module |
Solution 3 |
tuple struct constructor `Percent` is private |
la struct est pub, mais pas ses champs |
Solution 4 |
Ce que ça veut dire
Section intitulée « Ce que ça veut dire »Lisez les deux flèches. La première (ligne 8) montre l’endroit où vous utilisez l’élément. La flèche de la note: (ligne 2) montre l’endroit où l’élément est défini. Rust vous dit : « Je vois bien apply_discount là-bas, mais elle n’a jamais été marquée comme partagée, donc le code en dehors de billing ne peut pas l’appeler. »
Le fichier ne change rien. Si billing se trouve dans src/billing.rs, vous obtenez la même erreur, et la note: pointe simplement vers src/billing.rs:1:1.
Imaginez un immeuble de bureaux. Chaque module est une pièce avec une porte. Un élément privé est un outil qui reste dans sa pièce : les gens dans la pièce (et dans les petites pièces à l’intérieur) peuvent s’en servir, mais personne depuis le couloir. pub pose l’outil sur une étagère dans le couloir.
Pourquoi Rust fait ça
Section intitulée « Pourquoi Rust fait ça »Rust rend tout privé par défaut : les fonctions, les structs, les champs des structs, les modules et même les imports use. Vous choisissez de partager avec pub. La leçon Les modules le montre dès le début.
La raison, c’est la tranquillité du vous du futur. Tout ce qui est pub devient une promesse : d’autre code peut en dépendre, et le modifier peut casser ce code. Les éléments privés, eux, peuvent être modifiés, renommés ou supprimés librement, et le compilateur garantit que personne à l’extérieur ne s’en sert. Les petites fonctions d’aide restent des fonctions d’aide, et une struct peut protéger ses propres règles (comme « un solde n’est jamais négatif »), car personne d’autre ne peut toucher directement à ses champs.
Encore un détail : la visibilité est vérifiée à chaque étape d’un chemin. shop::prices::price_of ne fonctionne que si prices vous est visible et que price_of vous est visible. Une pub fn dans un module privé reste hors de portée.
Comment corriger
Section intitulée « Comment corriger »Solution 1 : ajouter pub à l’élément (et à chaque module sur le chemin)
Section intitulée « Solution 1 : ajouter pub à l’élément (et à chaque module sur le chemin) »Choisissez-la quand l’élément est fait pour être utilisé en dehors de son module. C’est la bonne correction la plupart du temps :
mod billing { pub fn apply_discount(price: u32) -> u32 { price * 90 / 100 }}
fn main() { let total = billing::apply_discount(200); println!("Total : {total}");}Sortie :
Total : 180Si l’erreur dit module `prices` is private, le pub manquant est sur le module : écrivez pub mod prices { ... }. Rustc vous le signale aussi avec une deuxième étiquette, function `price_of` is not publicly re-exported (la fonction n’est pas réexportée publiquement). Avec un fichier séparé, le pub va sur la ligne de déclaration : pub mod prices;.
Pour une struct, pub struct Order rend le type public, mais chaque champ a quand même besoin de son propre pub si le code extérieur doit le lire ou le modifier. Plus de détails dans la solution 4.
Solution 2 : utiliser pub(crate) ou pub(super) pour « mon code seulement »
Section intitulée « Solution 2 : utiliser pub(crate) ou pub(super) pour « mon code seulement » »Choisissez-la quand l’élément doit être partagé, mais pas avec le monde entier. pub a plusieurs niveaux, du plus petit au plus grand :
| Vous écrivez | Qui peut utiliser l’élément |
|---|---|
| rien (privé) | son propre module, et les modules qu’il contient |
pub(super) |
en plus, le module parent |
pub(crate) |
tout le code de cette crate |
pub |
tout le monde, y compris les autres crates qui dépendent de la vôtre |
Dans un programme (un binaire), pub(crate) et pub se comportent presque pareil. La différence compte dans une bibliothèque : pub(crate) permet à vos modules de partager une fonction d’aide sans en faire une partie de l’API publique de la bibliothèque.
mod shop { // Tout le code de cette crate peut l'appeler. pub(crate) fn store_name() -> &'static str { "Ferris Fruits" }
pub mod receipt { // Seul le module parent, `shop`, peut appeler cette fonction d'aide. 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!("Bienvenue chez {}", shop::store_name()); shop::print_receipt(&[("pomme", 3), ("poire", 5)]); // shop::receipt::line("pomme", 3); // ❌ E0603 : `line` est réservée à `shop`}Sortie :
Bienvenue chez Ferris Fruits== Ferris Fruits ==pomme : 3poire : 5Retirez le // devant la dernière ligne et vous obtenez function `line` is private, même si elle est marquée pub(super). main n’est pas le parent de receipt, alors la porte reste fermée.
Solution 3 : réexporter avec pub use
Section intitulée « Solution 3 : réexporter avec pub use »Choisissez-la quand le module intérieur est un détail interne, mais qu’un élément à l’intérieur doit être facile à atteindre. Gardez le module privé et placez l’élément sur un chemin plus court et public :
mod shop { mod prices { // reste privé : la façon de stocker les prix ne regarde que shop pub fn price_of(item: &str) -> u32 { if item == "pomme" { 3 } else { 5 } } }
pub use prices::price_of; // désormais accessible via shop::price_of}
fn main() { println!("Les pommes coûtent {}", shop::price_of("pomme")); println!("Les poires coûtent {}", shop::price_of("poire"));}Sortie :
Les pommes coûtent 3Les poires coûtent 5C’est aussi la correction pour function import `price_of` is private. Un simple use prices::price_of; dans shop est un raccourci réservé à shop ; comme tout le reste, un use est privé. pub use transforme le raccourci en porte publique. Les grosses crates font ça tout le temps : c’est pour ça que vous pouvez écrire serde::Serialize sans savoir dans quel module intérieur il se trouve.
Solution 4 : ajouter un pub fn new au lieu de rendre les champs publics
Section intitulée « Solution 4 : ajouter un pub fn new au lieu de rendre les champs publics »Choisissez-la quand l’erreur porte sur les champs d’une struct ou sur son constructeur. Ici, la struct est pub, mais pas son champ :
mod billing { pub struct Percent(u8);}
fn main() { let discount = billing::Percent(150); // ❌ constructeur privé}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); // ❌ constructeur privé | ^^^^^^^ private tuple struct constructor |help: consider making the field publicly accessible |2 | pub struct Percent(pub u8); | +++Rustc explique qu’un constructeur est privé dès qu’un des champs est privé, et propose de rendre le champ public avec pub u8. Pour un simple type de données, c’est très bien. Mais regardez la valeur : 150 pour cent ! Souvent, le champ privé est justement le but. Le module veut vérifier la valeur avant qu’un Percent existe. Donnez-lui un constructeur public qui fait la vérification :
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 avec 10 % de remise : {}", ten.apply(200)); println!("150 % est-il autorisé ? {}", billing::Percent::new(150).is_some());}Sortie :
200 avec 10 % de remise : 180150 % est-il autorisé ? falseDésormais, chaque Percent du programme est garanti entre 0 et 100, et apply ne peut jamais passer sous zéro (underflow). N’oubliez pas que new a lui aussi besoin de pub ; une méthode privée donne une autre erreur, E0624 (associated function `new` is private). Voir Les structs pour en savoir plus sur les constructeurs.
Où vous le verrez souvent
Section intitulée « Où vous le verrez souvent »Un paquet avec à la fois main.rs et lib.rs. Ce sont deux crates séparées, et main.rs utilise la bibliothèque depuis l’extérieur. Si lib.rs contient mod inventory;, alors use shop::inventory::count_items; dans main.rs échoue :
error[E0603]: module `inventory` is private --> src/main.rs:1:11 |1 | use shop::inventory::count_items; | ^^^^^^^^^ private moduleRustc dit que le module inventory est privé. Correction : écrivez pub mod inventory; dans lib.rs et pub fn count_items dans le module. Attention : pub(crate) ne suffit pas ici. Pour la bibliothèque, main.rs est une autre crate, donc une pub(crate) fn donne encore function `count_items` is private. Voir Cargo et les crates.
Les champs privés d’une struct. Ils ont leurs propres codes d’erreur. Créer une struct avec un champ privé donne E0451, et en lire un donne E0616 :
error[E0451]: field `balance` of struct `Account` is privateerror[E0616]: field `balance` of struct `Account` is privateLes deux disent que le champ balance de la struct Account est privé. Correction : le même choix que dans la solution 4. Ajoutez pub au champ si n’importe qui peut le modifier, ou gardez-le privé et ajoutez pub fn new(...) plus un accesseur comme pub fn balance(&self) -> u64.
Une fonction trouvée dans le code source d’une crate. Vous lisez une crate sur GitHub, vous trouvez la fonction d’aide parfaite, et vous obtenez E0603 en l’appelant. Si les auteurs de la crate ne l’ont pas rendue pub, vous ne pouvez pas l’utiliser, et ils peuvent la modifier à tout moment. Cherchez une façon publique de faire la même chose sur la page de la crate sur docs.rs ; seuls les éléments pub y apparaissent.
Erreurs liées
Section intitulée « Erreurs liées »- E0432 :
unresolved import(import non résolu). L’élément n’a pas été trouvé du tout. Avec E0603, il a été trouvé, mais il est privé. - E0433 :
failed to resolve(échec de résolution), un chemin dans votre code qui ne mène nulle part. - E0451 et E0616 : un champ de struct est privé (à la création de la struct, ou à la lecture du champ).
- E0624 : une méthode ou une fonction associée (comme
new) est privée. - Toutes les erreurs du compilateur : la liste complète des pages d’erreurs.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. mod shop { mod prices { pub fn price_of() {} } } et main appelle shop::prices::price_of(). Quelle erreur obtenez-vous ?
2. Une fonction d'aide dans src/lib.rs est marquée pub(crate). Est-ce que src/main.rs, dans le même paquet, peut l'appeler ?
3. Une pub struct Email(String); garde son champ privé exprès. Quelle est la façon la plus simple de permettre aux autres modules d'en créer une ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- E0603 — Rust error codes index (en anglais) : l’explication officielle, avec un exemple minimal.
- Paths for Referring to an Item in the Module Tree — The Rust Book (en anglais) : exposer des chemins avec
pub, et commentpubfonctionne sur les structs et les enums. - Bringing Paths into Scope with the
useKeyword — The Rust Book (en anglais) : réexporter des noms avecpub use. - Visibility — Rust by Example (en anglais) :
pub,pub(crate),pub(super)etpub(in path)dans un seul exemple exécutable. - Visibility and privacy — The Rust Reference (en anglais) : les règles exactes, quand vous voulez avoir une vue complète.