プライベートフィールド
CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 10/61。
前のレッスンでは、struct、そのフィールド、そしてそのメソッドをすべて public にしました。しかし、真のカプセル化とは、データをどのように access できるかを制御することです。Rust では、フィールドを private にしたまま、struct を public にできます。
負の balance を決して持たない Wallet を考えてみましょう。field が public なら、誰でも任意の値を設定できてしまいます。
// wallet.rs
pub struct Wallet {
balance: f64, // No pub = private!
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Wallet { balance: initial }
}
}
Wallet は public ですが、balance には pub キーワードがありません。つまり、モジュール外のコードでは constructor を使って Wallet を作成できますが、balance field を直接 read したり変更したりすることはできません。
// main.rs
mod wallet;
use wallet::Wallet;
fn main() {
let w = Wallet::new(100.0);
// println!("{}", w.balance); // Error! フィールドはプライベートです
// w.balance = -50.0; // Error! プライベートフィールドにアクセスできません
}
これはカプセル化の基盤です。struct は自身のデータを管理します。外部コードは、あなたが提供するメソッドを経由しなければなりません。つまり、検証、ロギング、その他のロジックを追加できます。データは無効な状態から保護されたままになります。
これからのレッスンでは、getterメソッドとsetterメソッドを通じて、このprivateデータへの制御されたaccessを提供する方法を学びます。
チャレンジ
簡単モジュール内で機密データを保護することでカプセル化を示す、温度センサーシステムを構築しましょう。
コードを整理するために、2つのファイルを作成します。
sensor.rs: 2つのfield、location(String)とreading(f64)を持つTemperatureSensorstructをDefineします。structは他のファイルから使用できるようにpublicにしますが、両方のfieldはprivateのままにします。外部コードからセンサーのデータに直接accessしたり変更したりできないようにするためです。location nameとinitial temperature readingをTakesするpublicなnewconstructorを追加します。main.rs: sensor moduleを読み込み、constructorをusingしてTemperatureSensorを作成します。fieldはprivateなので直接printingすることはできません。代わりに、sensorが正常にcreatedされたことを示すconfirmation messageをprintingします。
このchallengeでは、private fieldのcore conceptに焦点を当てます。structにはaccessできますが、その内部データは保護されています。外部コードは、提供されたmethod(この場合はconstructorのみ)を通じてのみsensorとやり取りできます。
出力は次のexact formatに従う必要があります。
Sensor created for: {location}printingのためにlocationにaccessするには、field自体がprivateなので、sensorをreturnする前にnew functionでこのmessageをprintingする必要があります。
たとえば、location "Kitchen"、reading 22.5でsensorを作成すると、出力は次のようになります。
Sensor created for: Kitchen2つの入力を受け取ります。location nameとinitial temperature readingです。
REQUIRED OUTPUT FORMAT:自分で試してみよう
mod sensor;
use sensor::TemperatureSensor;
fn main() {
// 入力を読み取る
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: コンストラクタを使用してTemperatureSensorを作成する
// new関数が確認メッセージの出力を処理します
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rustオンラインコンパイラ