Private Felder
Teil des Abschnitts Object Oriented Programming der Rust-Journey von Coddy — Lektion 10 von 61.
In der vorherigen Lektion haben Sie alles öffentlich gemacht – das Struct, seine Felder und seine Methoden. Aber echte Kapselung bedeutet zu kontrollieren, wie auf Ihre Daten zugegriffen werden kann. In Rust können Sie ein Struct öffentlich machen, während Sie seine Felder privat halten.
Betrachten wir eine Wallet, die niemals einen negativen Kontostand haben sollte. Wenn das Feld öffentlich wäre, könnte jeder es auf einen beliebigen Wert setzen:
// wallet.rs
pub struct Wallet {
balance: f64, // Kein pub = privat!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
Beachten Sie, dass Wallet öffentlich ist, aber balance kein pub-Schlüsselwort hat. Dies bedeutet, dass Code außerhalb des Moduls ein Wallet mit dem Konstruktor erstellen kann, aber das balance-Feld nicht direkt lesen oder ändern kann:
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // Fehler! Feld ist privat
// w.balance = -50.0; // Fehler! Zugriff auf privates Feld nicht möglich
}
Dies ist die Grundlage der Kapselung – das Struct kontrolliert seine eigenen Daten. Externer Code muss über die von Ihnen bereitgestellten Methoden gehen, was bedeutet, dass Sie Validierung, Logging oder jede andere Logik hinzufügen können. Die Daten bleiben vor ungültigen Zuständen geschützt.
In den kommenden Lektionen werden Sie lernen, wie Sie über Getter- und Setter-Methoden einen kontrollierten Zugriff auf diese privaten Daten ermöglichen.
Aufgabe
EinfachLassen Sie uns ein Temperatursensorsystem bauen, das Kapselung demonstriert, indem sensible Daten innerhalb eines Moduls geschützt werden.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
sensor.rs: Definieren Sie einTemperatureSensor-Struct mit zwei Feldern:location(String) undreading(f64). Das Struct sollte öffentlich sein, damit es von anderen Dateien aus verwendet werden kann, aber halten Sie beide Felder privat – externer Code sollte nicht direkt auf die Daten des Sensors zugreifen oder diese ändern können. Fügen Sie einen öffentlichennew-Konstruktor hinzu, der einen Standortnamen und einen ersten Temperaturmesswert entgegennimmt.main.rs: Binden Sie Ihr Sensormodul ein und erstellen Sie einenTemperatureSensormit dem Konstruktor. Da die Felder privat sind, können Sie diese nicht direkt ausgeben – geben Sie stattdessen eine Bestätigungsmeldung aus, die zeigt, dass der Sensor erfolgreich erstellt wurde.
Diese Herausforderung konzentriert sich auf das Kernkonzept privater Felder: Das Struct ist zugänglich, aber seine internen Daten sind geschützt. Externer Code kann nur über die von Ihnen bereitgestellten Methoden (in diesem Fall nur der Konstruktor) mit dem Sensor interagieren.
Ihre Ausgabe sollte genau diesem Format folgen:
Sensor created for: {location}Um auf den Standort für die Ausgabe zuzugreifen, müssen Sie Ihre new-Funktion diese Nachricht ausgeben lassen, bevor der Sensor zurückgegeben wird, da das Feld selbst privat ist.
Wenn Sie beispielsweise einen Sensor mit dem Standort "Kitchen" und dem Messwert 22.5 erstellen, wäre die Ausgabe:
Sensor created for: KitchenSie erhalten zwei Eingaben: den Standortnamen und den anfänglichen Temperaturmesswert.
Spickzettel
In Rust können Sie ein Struct öffentlich machen, während Sie dessen Felder privat halten, um Kapselung zu erreichen. Dies verhindert, dass externer Code direkt auf die internen Daten zugreift oder diese modifiziert.
Um ein Feld privat zu machen, lassen Sie einfach das Schlüsselwort pub weg:
pub struct Wallet {
balance: f64, // Kein pub = privates Feld
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
In diesem Beispiel ist Wallet öffentlich (kann außerhalb des Moduls verwendet werden), aber balance ist privat (kann nicht direkt von außen zugegriffen werden).
Externer Code kann Instanzen über öffentliche Konstruktoren erstellen, aber keine privaten Felder lesen oder modifizieren:
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // Fehler! Feld ist privat
// w.balance = -50.0; // Fehler! Zugriff auf privates Feld nicht möglich
}
Diese Kapselung stellt sicher, dass das Struct seine eigenen Daten kontrolliert und externer Code die von Ihnen bereitgestellten Methoden verwenden muss, um damit zu interagieren.
Probier es selbst
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// Eingabe lesen
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: Erstellen Sie einen TemperatureSensor mit dem Konstruktor
// Die neue Funktion übernimmt das Drucken der Bestätigungsnachricht
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Methoden und Verhalten
Einführung in ImplementierungsblöckeDer Self-ParameterVeränderliche MethodenAssoziierte FunktionenMehrere ImplementierungsblöckeMethod ChainingRückblick – Rechteck-Aktionen4Projekt: Virtuelles Haustier
Das Haustier definierenDas Haustier füttern7Standard-Traits
Das Debug-TraitDas Display-TraitClone und CopyGleichheits-TraitsZusammenfassung – Druckbarer Punkt10Projekt: Dokumentensystem
Das Draw-TraitText-Komponente2Kapselung und Module
Grundlagen der ModuleDas Public-SchlüsselwortPrivate FelderGetterSetterWiederholung – Sicherer Tresor5Generics
Generische StructsGenerische MethodenMehrere generische TypenGenerische FunktionenZusammenfassung - Koordinatenpunkt8Traits als Einschränkungen
Syntax für Trait BoundsMehrfache BoundsDie Where-KlauselTypen mit Traits zurückgebenRückblick – Generischer Drucker11Design Patterns in Rust
Newtype-PatternKompositionDas Drop-TraitFrom und IntoZusammenfassung – Smart Pointer Mock3Fortgeschrittene Enums
Enums mit DatenMethoden für EnumsMatching von DatenvariantenDas Option-Enum erneut betrachtetZusammenfassung – Shape-Enum6Definition von Traits
Was ist ein Trait?Traits implementierenStandardimplementierungenStandardimplementierungen überschreibenTraits mit ParameternZusammenfassung – Media Player