Campi privati
Fa parte della sezione Programmazione orientata agli oggetti del percorso Rust di Coddy. Lezione 10 di 61.
Nella lezione precedente, hai reso tutto pubblico: la struct, i suoi campi e i suoi metodi. Ma la vera incapsulazione significa controllare come è possibile accedere ai tuoi dati. In Rust, puoi rendere pubblica una struct mantenendo privati i suoi campi.
Considera un Wallet che non dovrebbe mai avere un saldo negativo. Se il campo è pubblico, chiunque potrebbe impostarlo su qualsiasi valore:
// wallet.rs
pub struct Wallet {
balance: f64, // Senza pub = privato!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
Nota che Wallet è pubblico, ma balance non ha la parola chiave pub. Questo significa che il codice esterno al modulo può creare un Wallet usando il costruttore, ma non può leggere o modificare direttamente il campo balance:
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // Errore! Il campo è privato
// w.balance = -50.0; // Errore! Impossibile accedere al campo privato
}
Questa è la base dell'incapsulamento: la struct controlla i propri dati. Il codice esterno deve passare attraverso i metodi che fornisci, il che significa che puoi aggiungere convalida, registrazione o qualsiasi altra logica. I dati restano protetti da stati non validi.
Nelle prossime lezioni imparerai come fornire un accesso controllato a questi dati privati tramite metodi getter e setter.
Sfida
FacileCostruiamo un sistema di sensori di temperatura che dimostra l'incapsulamento mantenendo i dati sensibili protetti all'interno di un modulo.
Creerai due file per organizzare il codice:
sensor.rs: Definisci una structTemperatureSensorcon due campi:location(String) ereading(f64). La struct deve essere pubblica, così da poter essere usata da altri file, ma mantieni privati entrambi i campi: il codice esterno non dovrebbe poter accedere direttamente ai dati del sensore né modificarli. Aggiungi un costruttore pubbliconewche accetti il nome di una località e una lettura iniziale della temperatura.main.rs: Includi il modulo del sensore e crea unTemperatureSensorusando il costruttore. Poiché i campi sono privati, non potrai stamparli direttamente; stampa invece un messaggio di conferma che indichi che il sensore è stato creato correttamente.
Questa sfida si concentra sul concetto fondamentale dei campi privati: la struct è accessibile, ma i suoi dati interni sono protetti. Il codice esterno può interagire con il sensore solo tramite i metodi che fornisci (in questo caso, soltanto il costruttore).
L'output deve seguire esattamente questo formato:
Sensor created for: {location}Per accedere alla località da stampare, dovrai fare in modo che la funzione new stampi questo messaggio prima di restituire il sensore, poiché il campo è privato.
Ad esempio, se crei un sensore con la località "Kitchen" e una lettura di 22.5, l'output sarà:
Sensor created for: KitchenRiceverai due input: il nome della località e la lettura iniziale della temperatura.
Provalo tu
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// Leggi l'input
let mut location = String::new();
std::io::stdin().read_line(&mut location).expect("Failed to read line");
let location = location.trim().to_string();
let mut reading_str = String::new();
std::io::stdin().read_line(&mut reading_str).expect("Failed to read line");
let reading: f64 = reading_str.trim().parse().expect("Failed to parse reading");
// TODO: Crea un TemperatureSensor usando il costruttore
// La funzione new si occuperà di stampare il messaggio di conferma
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Metodi e comportamento
Introduzione ai blocchi implIl parametro selfMetodi mutabiliFunzioni associateBlocchi impl multipliConcatenamento di metodiRiepilogo - Azioni sul rettangolo4Progetto: animale domestico virtuale
Definire l'animaleNutrire l'animale7Trait standard
Il trait DebugIl trait DisplayClone e CopyTrait di uguaglianzaRiepilogo - Punto stampabile10Progetto: sistema di documenti
Il trait DrawComponente di testo2Incapsulamento e moduli
Nozioni di base sui moduliLa parola chiave publicCampi privatiGetterSetterRiepilogo - Armadietto sicuro5Generics
Struct genericheMetodi genericiPiù tipi genericiFunzioni genericheRipasso - Punto di coordinate8I Trait come vincoli
Sintassi dei vincoli sui traitVincoli multipliLa clausola whereRestituire tipi con i traitRiepilogo - Stampante generica11Modelli di progettazione in Rust
Pattern NewtypeComposizioneIl trait DropFrom e IntoRipasso - Mock con smart pointer3Enumerazioni avanzate
Enumerazioni con datiMetodi sulle enumerazioniCorrispondenza delle varianti con datiL'enumerazione Option ripresaRiepilogo - enumerazione Shape6Definizione dei trait
Che cos’è un trait?Implementare i traitImplementazioni predefiniteSovrascrivere le implementazioni predefiniteTrait con parametriRiepilogo - Lettore multimedialeEsercitati da solo: Compilatore Rust online