セッター
CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 12/61。
ゲッターを使うと、外部コードから private データをreadできます。しかし、それを変更できるようにする必要がある場合はどうでしょうか?そこで登場するのがsetter methodsです。これは、private field を制御された方法で変更する public メソッドです。
基本的な setter は &mut self と新しい値を受け取ります:
// wallet.rs
pub struct Wallet {
balance: f64,
}
impl Wallet {
pub fn new(initial: f64) -> Wallet {
Self { balance: initial }
}
pub fn balance(&self) -> f64 {
self.balance
}
pub fn set_balance(&mut self, amount: f64) {
self.balance = amount;
}
}
getterとは異なり、Rustのsetterでは通常、データを変更することを明確に示すためにset_接頭辞を使用します。&mut selfパラメーターは不可欠です。これにより、メソッドに構造体のフィールドを変更する許可が与えられます。
セッターの真の力は検証です。どんな値でも無条件に受け入れるのではなく、ルールを適用できます。
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// 負の値は黙って無視されます
}
これでウォレットは自らを保護します。外部コードがどのような値を設定しようとしても、balance が負になることは決してありません。これがカプセル化の実践です。構造体が自身の不変条件を管理するため、外部コードが無効な状態にすることは単純にできません。
チャレンジ
簡単setter がデータを有効に保つためのルールを適用できることを示す、サーモスタットシステムを構築しましょう。サーモスタットには、safe range 内でのみ調整できる temperature setting があります。
コードを整理するために、2つのファイルを作成します。
thermostat.rs: private なtemperaturefield (i32) を持つThermostatstruct を Define します。struct は public にしますが、field は invalid values から保護するため private のままにします。以下を Implement します。- initial temperature を受け取る
newconstructor - current temperature を returns する
temperaturegetter - 10 と 30 の between (inclusive) の values のみを受け入れる
set_temperaturesetter。この range の outside の value の場合、temperature は unchanged のままにします。
- initial temperature を受け取る
main.rs: thermostat module を読み込み、thermostat を作成し、さまざまな temperature の設定を Attempt して各 Attempt 後に result を出力することで、setter の validation を示します。
setter は invalid values を silently ignore する必要があります。error messages は表示せず、valid range の outside にある値を設定しようとした場合は current temperature をそのまま keep します。
出力は次の exact format に従う必要があります。
Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}たとえば、20 で thermostat を作成し、その後 25 (valid)、さらに 50 (invalid) に設定しようとした場合、出力は次のようになります。
Initial: 20
After setting to 25: 25
After setting to 50: 253つの inputs を受け取ります。initial temperature、最初に設定を Attempt する temperature、そして2番目に設定を Attempt する temperature です。
自分で試してみよう
mod thermostat;
use thermostat::Thermostat;
fn main() {
// 入力を読み取る
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_temp: i32 = input1.trim().parse().expect("Invalid number");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let first_attempt: i32 = input2.trim().parse().expect("Invalid number");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let second_attempt: i32 = input3.trim().parse().expect("Invalid number");
// TODO: 初期温度でサーモスタットを作成する
// TODO: 初期温度を出力する
// フォーマット: "Initial: {temperature}"
// TODO: 最初の温度の設定を試み、結果を出力する
// Format: "After setting to {attempted_value}: {temperature}"
// TODO: 2番目の温度の設定を試み、結果を出力する
// Format: "After setting to {attempted_value}: {temperature}"
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rustオンラインコンパイラ