Errore Rust E0624: method is private (metodo privato)
E0624 significa: il metodo che hai chiamato esiste, ma è stato scritto senza pub, quindi può chiamarlo solo il codice dentro il suo modulo. La struct può essere pubblica, e anche il modulo. I metodi però partono comunque privati, uno per uno. Succede spessissimo subito dopo aver spostato un tipo in un modulo tutto suo, e di solito la soluzione è aggiungere pub davanti a fn. Questa pagina fa parte della guida agli errori del compilatore.
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”error[E0624]: associated function `new` is private --> src/main.rs:18:38 | 7 | fn new() -> Account { // no `pub` | ------------------- private associated function defined here...18 | let mut account = bank::Account::new(); // ❌ private associated function | ^^^ private associated function
error[E0624]: method `add_interest` is private --> src/main.rs:19:13 |11 | fn add_interest(&mut self) { // no `pub` | -------------------------- private method defined here...19 | account.add_interest(); // ❌ private method | ^^^^^^^^^^^^ private methodIl compilatore ti dice: «la funzione associata new è privata» e «il metodo add_interest è privato», e per ciascuno ti mostra dove è definito.
Ecco il programma che lo provoca:
mod bank { pub struct Account { balance: u64, }
impl Account { fn new() -> Account { // no `pub` Account { balance: 0 } }
fn add_interest(&mut self) { // no `pub` self.balance += self.balance / 100; } }}
fn main() { let mut account = bank::Account::new(); // ❌ private associated function account.add_interest(); // ❌ private method}(I commenti dicono: manca pub; funzione associata privata; metodo privato.)
Qui rustc usa due nomi. Un metodo (method) riceve self (account.add_interest()). Una funzione associata (associated function) non ha self e si chiama con :: (Account::new()). La regola e la soluzione sono le stesse per entrambi.
Cosa significa
Sezione intitolata “Cosa significa”Ogni errore ha due frecce. La freccia ^^^ è la tua chiamata. La freccia --- mostra la riga fn a cui manca pub. Quindi il messaggio ti dice esattamente dove aggiungerlo.
Stare dentro impl Account non rende pubblico un metodo, nemmeno quando Account è pub. Pensa a un ristorante: il menù è pubblico, quindi puoi ordinare i piatti (i metodi pub). La cucina ha i suoi passaggi, come «tritare le cipolle», che non puoi chiedere direttamente. Quelli sono i metodi privati.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”In Rust tutto è privato per impostazione predefinita, e i metodi non fanno eccezione (vedi Moduli). La privacy appartiene al modulo in cui è scritto il blocco impl: qualsiasi codice in mod bank può chiamare add_interest, il codice fuori no.
Così un tipo può tenersi piccoli metodi di supporto che hanno senso solo nell’ordine giusto. Immagina che add_interest debba essere eseguito una volta al mese, dopo l’addebito delle commissioni. Se chiunque potesse chiamarlo, prima o poi qualcuno lo chiamerebbe due volte per sbaglio. Metodi di supporto privati più un metodo pubblico che li esegue nel modo giusto rendono quell’errore impossibile.
Inoltre ti lascia libero di cambiare idea. I metodi privati si possono rinominare, unire o cancellare in qualsiasi momento, perché il compilatore garantisce che nessun codice esterno li usa.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: aggiungi pub al metodo
Sezione intitolata “Soluzione 1: aggiungi pub al metodo”Scegli questa strada quando il metodo è pensato per essere chiamato da fuori. Per new è quasi sempre così: un costruttore che nessuno può chiamare non serve a molto.
mod bank { pub struct Account { balance: u64, }
impl Account { pub fn new(opening: u64) -> Account { Account { balance: opening } }
pub fn add_interest(&mut self) { self.balance += self.balance / 100; // 1% }
pub fn balance(&self) -> u64 { self.balance } }}
fn main() { let mut account = bank::Account::new(1000); account.add_interest(); println!("Saldo: {}", account.balance());}Output:
Saldo: 1010Soluzione 2: chiama il metodo pubblico pensato per te
Sezione intitolata “Soluzione 2: chiama il metodo pubblico pensato per te”Scegli questa strada quando il metodo privato è un metodo di supporto, soprattutto nel codice che non hai scritto tu. Spesso c’è un metodo pubblico che lo chiama per te, nell’ordine giusto e con i controlli giusti. Qui tenere add_interest privato è il progetto corretto:
mod bank { pub struct Account { balance: u64, }
impl Account { pub fn new(opening: u64) -> Account { Account { balance: opening } }
// La porta d'ingresso pubblica: una chiamata fa tutto il mese, nell'ordine giusto. pub fn close_month(&mut self) { self.charge_fee(); self.add_interest(); }
pub fn balance(&self) -> u64 { self.balance }
// Metodi di supporto privati: chiamarli da soli, o due volte, dà risultati sbagliati. fn charge_fee(&mut self) { self.balance = self.balance.saturating_sub(5); }
fn add_interest(&mut self) { self.balance += self.balance / 100; } }}
fn main() { let mut account = bank::Account::new(1000); account.close_month(); println!("Dopo un mese: {}", account.balance()); // account.add_interest(); // ❌ E0624: il metodo `add_interest` è privato}Output:
Dopo un mese: 1004Una buona regola: rendi pub un metodo solo se chiamarlo da solo, in qualsiasi momento non può rompere la struct. Se ha senso solo come un passo di qualcosa di più grande, tienilo privato ed esponi la cosa più grande.
Soluzione 3: usa pub(crate) per «solo il mio codice»
Sezione intitolata “Soluzione 3: usa pub(crate) per «solo il mio codice»”Scegli questa strada quando il metodo serve ad altri moduli del tuo crate, ma non deve vederlo chi usa la tua libreria. pub(super) (solo il modulo genitore) funziona allo stesso modo; la pagina di E0603 ha una tabella con tutti i livelli.
mod shop { pub struct Cart { prices: Vec<u32>, }
impl Cart { pub fn new() -> Cart { Cart { prices: Vec::new() } }
pub fn add(&mut self, price: u32) { self.prices.push(price); }
// Solo per il nostro codice (come le ricevute), non per chi usa la libreria. pub(crate) fn total(&self) -> u32 { self.prices.iter().sum() } }}
mod receipt { pub fn print(cart: &crate::shop::Cart) { println!("Totale: {}", cart.total()); }}
fn main() { let mut cart = shop::Cart::new(); cart.add(3); cart.add(5); receipt::print(&cart);}Output:
Totale: 8Un’avvertenza: in un pacchetto con sia src/lib.rs sia src/main.rs, quelli sono due crate. Una pub(crate) fn total in lib.rs è privata per main.rs:
error[E0624]: method `total` is private --> src/main.rs:3:25 | 3 | println!("{}", cart.total()); | ^^^^^ private method | ::: src/lib.rs:10:5 |10 | pub(crate) fn total(&self) -> u32 { | --------------------------------- private method defined hereLì usa un semplice pub. Vedi Cargo e crate.
Soluzione 4: sposta nel modulo il codice che ne ha bisogno
Sezione intitolata “Soluzione 4: sposta nel modulo il codice che ne ha bisogno”Scegli questa strada quando il metodo deve davvero restare privato, ma a del codice serve comunque, come un controllo di verifica o un test. Il codice nello stesso modulo può chiamarlo, e anche un modulo figlio: i moduli dentro bank vedono tutto ciò che è privato in bank.
mod bank { pub struct Account { balance: u64, }
impl Account { pub fn new(opening: u64) -> Account { Account { balance: opening } }
fn is_suspicious(&self) -> bool { self.balance > 10_000 } }
// Un modulo figlio può usare tutto ciò che è privato nel genitore. pub mod audit { pub fn check(account: &super::Account) -> &'static str { if account.is_suspicious() { "da controllare" } else { "ok" } } }}
fn main() { let small = bank::Account::new(500); let big = bank::Account::new(50_000); println!("piccolo: {}", bank::audit::check(&small)); println!("grande: {}", bank::audit::check(&big));}Output:
piccolo: okgrande: da controllareI test unitari funzionano allo stesso modo. Un mod tests scritto dentro bank (o in fondo a src/bank.rs) è un modulo figlio, quindi può chiamare i metodi privati. Vedi Test:
#[cfg(test)]mod tests { use super::*;
#[test] fn not_suspicious_when_small() { let account = Account::new(500); assert!(!account.is_suspicious()); // privato, ma qui è permesso }}Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Un blocco impl in un altro modulo. La privacy appartiene al modulo in cui è scritto l’impl, non alla struct. Se Order vive in mod model ma scrivi impl Order { fn with_tax(&self) ... } dentro mod pricing, allora main ottiene method `with_tax` is private, che indica mod pricing. Soluzione: pub fn with_tax, oppure pub(crate).
Usare un metodo come valore funzione. accounts.iter().map(bank::Account::audit) è la stessa chiamata scritta in un altro modo, quindi dà lo stesso E0624. Stessa soluzione.
I metodi dei trait. Non scrivi mai pub sui metodi dentro impl SomeTrait for Type. Sono pubblici quanto il trait, e aggiungere pub è un errore: error[E0449]: visibility qualifiers are not permitted here. Se sembra mancare un metodo di un trait, ottieni invece E0599, e la soluzione è importare il trait con use.
Il metodo privato di un crate. Hai trovato il metodo perfetto nel codice sorgente di un crate su GitHub, ma non è pub. Non puoi chiamarlo, e i suoi autori possono cambiarlo in qualsiasi versione. Cerca un metodo pubblico che faccia il lavoro sulla pagina del crate su docs.rs; lì compaiono solo gli elementi pub.
Errori correlati
Sezione intitolata “Errori correlati”- E0603:
function `x` is private. La stessa idea per funzioni libere, struct e moduli. - E0616:
field `x` of struct `Y` is private, quando leggi o scrivi un campo. - E0451: un campo privato mentre costruisci una struct con
Y { ... }. Di solito si risolve con unapub fn new. - E0599:
no method named `x` found. Il metodo non esiste per quel tipo, oppure il suo trait non è in scope. - Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. pub struct Timer ha impl Timer { fn start() -> Timer { ... } } dentro mod clock. Cosa succede quando main chiama clock::Timer::start()?
2. Quale codice può chiamare un metodo privato definito in mod bank?
3. Un add_interest privato deve essere eseguito solo una volta al mese, dopo le commissioni. Qual è la soluzione migliore per E0624?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0624 — Rust error codes index (in inglese): la spiegazione ufficiale con un esempio minimo.
- Method Syntax — The Rust Book (in inglese): metodi, funzioni associate e blocchi
impl. - Paths for Referring to an Item in the Module Tree — The Rust Book (in inglese): rendere visibili gli elementi con
pub, passo dopo passo. - Testing Private Functions — The Rust Book (in inglese): perché i test unitari possono chiamare il codice privato.
- Visibility and privacy — The Rust Reference (in inglese): le regole esatte, compresi
pub(crate),pub(super)epub(in path).