Salta ai contenuti

Errore Rust E0616: field of struct is private (campo privato)

E0616 significa: il campo che hai chiesto esiste, ma è privato del modulo in cui è definita la struct. Puoi tenere in mano la struct, ma non frugarci dentro. Capita a tutti la prima volta che spostano una struct in un modulo tutto suo, e a tutti quelli che scrivono v.len invece di v.len(). Di solito la soluzione è una chiamata di metodo. Questa pagina fa parte della guida agli errori del compilatore.

error[E0616]: field `balance` of struct `Account` is private
--> src/main.rs:16:50
|
16 | println!("{} has {}", account.owner, account.balance); // ❌ private field
| ^^^^^^^ private field

Il compilatore ti dice: «il campo balance della struct Account è privato».

Ecco il programma che lo provoca:

mod bank {
pub struct Account {
pub owner: String,
balance: u64, // private
}
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); // ❌ private field
}

Lo stesso errore si presenta in qualche variante:

Cosa hai scritto Cosa dice rustc Soluzione
account.balance field `balance` of struct `Account` is private Soluzione 2 o 3
scores.len su un Vec field `len` of struct `Vec` is private, più help: a method `len` also exists, call it with parentheses Soluzione 1
timeout.secs su una Duration field `secs` of struct `Duration` is private Soluzione 1 (as_secs())
account.balance = 500 lo stesso E0616: anche la scrittura è bloccata Soluzione 2

La freccia indica il nome del campo dopo il punto. account.owner sulla stessa riga va bene, perché owner è marcato pub. balance no, quindi solo il codice dentro mod bank può leggerlo o modificarlo.

Nota che Account stesso è pub. È questo che sorprende: rendere pubblica una struct non rende pubblici i suoi campi. Ogni campo ha il suo pub, oppure resta privato.

Pensa a una banca. Puoi entrare, e chiunque può vedere il nome sul tuo conto. Ma non puoi andare dietro lo sportello e aprire la cassaforte per contare i soldi. Lo chiedi all’impiegato, e l’impiegato segue le regole della banca.

In Rust tutto è privato per impostazione predefinita: funzioni, moduli, e anche i campi delle struct (vedi Moduli). La privacy riguarda i moduli, non i tipi. Qualsiasi codice dentro mod bank può toccare balance, e il codice fuori no.

Lo scopo è permettere a una struct di difendere le proprie regole. Diciamo che il saldo di un conto non deve mai andare sotto zero. Se ogni parte del programma potesse scrivere account.balance = ..., chiunque potrebbe violare quella regola, e dovresti cercare in tutto il codice per scoprire chi è stato. Se il campo è privato, solo i pochi metodi dentro mod bank possono cambiarlo. Controlli la regola lì, e vale ovunque. Questa idea si chiama incapsulamento.

La libreria standard fa lo stesso. Un Vec ha campi privati per la sua lunghezza e per il suo buffer di memoria. Se potessi scrivere v.len = 100 su un vettore che contiene 3 elementi, leggere v[50] leggerebbe memoria a caso. Tenere len privato è ciò che rende Vec sicuro da usare.

Soluzione 1: chiama il metodo invece di leggere il campo

Sezione intitolata “Soluzione 1: chiama il metodo invece di leggere il campo”

Scegli questa strada quando la struct arriva dalla libreria standard o da un altro crate. Non puoi cambiare il loro codice, e ti danno sempre dei metodi per ciò che puoi vedere. Quando rustc dice help: a method ... also exists, aggiungi le ():

use std::time::Duration;
fn main() {
let scores = vec![10, 20, 30];
println!("{} punteggi", scores.len());
let timeout = Duration::from_secs(90);
println!("Timeout: {} secondi", timeout.as_secs());
}

Output:

3 punteggi
Timeout: 90 secondi
▶ Provalo tu

Il nome del metodo non è sempre il nome del campo (secs si legge con as_secs()). Guarda la pagina del tipo su docs.rs, oppure lascia che il tuo editor elenchi i metodi dopo aver scritto il punto.

Soluzione 2: aggiungi un getter, e metodi che rispettano le regole

Sezione intitolata “Soluzione 2: aggiungi un getter, e metodi che rispettano le regole”

Scegli questa strada quando la struct è tua e il campo ha una regola da proteggere. Tieni il campo privato, aggiungi una pub fn che ne restituisce il valore (un getter), e modificalo solo con metodi che controllano la regola:

mod bank {
pub struct Account {
pub owner: String,
balance: i64, // privato: solo questo modulo può cambiarlo
}
impl Account {
pub fn new(owner: &str) -> Account {
Account { owner: owner.to_string(), balance: 0 }
}
// Getter: chiunque può leggere il saldo.
pub fn balance(&self) -> i64 {
self.balance
}
pub fn deposit(&mut self, amount: i64) {
if amount > 0 {
self.balance += amount;
}
}
// La regola vive qui: il saldo non va mai sotto zero.
pub fn withdraw(&mut self, amount: i64) -> Result<(), String> {
if amount > self.balance {
return Err(format!("solo {} disponibili", self.balance));
}
self.balance -= amount;
Ok(())
}
}
}
fn main() {
let mut account = bank::Account::new("Ferris");
account.deposit(100);
println!("{} ha {}", account.owner, account.balance());
match account.withdraw(500) {
Ok(()) => println!("Prelevati 500"),
Err(e) => println!("Impossibile prelevare 500: {e}"),
}
println!("Il saldo è ancora {}", account.balance());
}

Output:

Ferris ha 100
Impossibile prelevare 500: solo 100 disponibili
Il saldo è ancora 100
▶ Provalo tu

Rust permette a un metodo e a un campo di avere lo stesso nome, quindi balance() è il nome abituale per il getter (non get_balance()). Una volta che il getter esiste, rustc lo suggerisce persino: help: a method `balance` also exists, call it with parentheses. deposit e withdraw sono i tuoi setter: cambiano il campo, ma solo nei modi permessi dalle regole. Vedi Struct per saperne di più sui metodi.

Soluzione 3: rendi il campo pub quando i dati sono semplici

Sezione intitolata “Soluzione 3: rendi il campo pub quando i dati sono semplici”

Scegli questa strada quando qualsiasi valore va bene e nient’altro dipende dal campo. Un punto su una griglia, un colore o una struct di impostazioni non hanno regole da proteggere. Lì i getter sono solo codice in più da scrivere:

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!("Punto in ({}, {})", p.x, p.y);
}

Output:

Punto in (4, 4)
▶ Provalo tu

Quando il campo deve vederlo solo il tuo codice, scrivi pub(crate) x: i32 (qualsiasi modulo di questo crate) o pub(super) x: i32 (solo il modulo genitore). In un programma si comportano come pub; in una libreria tengono il campo fuori dalla tua API pubblica. La pagina di E0603 ha una tabella con tutti i livelli.

Conviene renderlo semplicemente pub? Chiediti: «Un certo valore di questo campo, o una sua modifica da sola, potrebbe rendere sbagliata la struct?» Un saldo negativo, una len che non corrisponde ai dati, un total che non è più la somma degli articoli: tienili privati e usa la Soluzione 2. Se la risposta è «no, qualsiasi valore va bene», pub è la scelta onesta.

len su un Vec. Hai scritto scores.len e hai ottenuto field `len` of struct `Vec` is private. Succede perché Vec ha davvero un campo privato chiamato len. La soluzione è scores.len(). Dettaglio curioso: name.len su una String dà un errore diverso, E0615 (attempted to take value of method), perché String non ha un campo con quel nome. Stessa soluzione.

Impostare un campo da fuori. Anche account.balance = 500; dà E0616. Pure la scrittura è bloccata. Non rendere il campo pub solo per impostarlo; aggiungi un metodo come deposit che fa la modifica e la controlla.

Dopo aver spostato una struct in un suo modulo o file. Il codice in main.rs usava user.email da mesi. Poi hai spostato User in src/user.rs e si è rotto ogni accesso ai campi. I campi che prima andavano bene ora sono privati di mod user. Aggiungi pub ai campi che sono semplici dati, e dei getter per gli altri.

I test. Un blocco #[cfg(test)] mod tests nello stesso file è un modulo figlio, quindi può leggere i campi privati. I test nella cartella tests/ stanno fuori dal tuo crate e possono usare solo l’API pub, come qualsiasi altro utente.

  • E0603: function `x` is private. La stessa idea per funzioni, struct e moduli.
  • E0451: lo stesso campo privato, ma mentre crei la struct con Account { ... }.
  • E0624: method `x` is private. Anche il metodo (o new) ha bisogno di pub.
  • E0609: no field `x` on type `T` . Il campo non esiste proprio (spesso è un errore di battitura).
  • E0615: attempted to take value of method. Hai scritto x.len e intendevi x.len().
  • Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.

Verifica veloce

1. pub struct Account { balance: u64 } è in mod bank. main può leggere account.balance?

2. Ottieni `field len of struct Vec is private`. Qual è la soluzione?

3. Una struct Score ha un campo points che deve restare tra 0 e 100. Qual è il progetto migliore?

Punteggio: 0 / 3