Menu
Coddy logo textTech

セッター

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 が負になることは決してありません。これがカプセル化の実践です。構造体が自身の不変条件を管理するため、外部コードが無効な状態にすることは単純にできません。

challenge icon

チャレンジ

簡単

setter がデータを有効に保つためのルールを適用できることを示す、サーモスタットシステムを構築しましょう。サーモスタットには、safe range 内でのみ調整できる temperature setting があります。

コードを整理するために、2つのファイルを作成します。

  • thermostat.rs: private な temperature field (i32) を持つ Thermostat struct を Define します。struct は public にしますが、field は invalid values から保護するため private のままにします。以下を Implement します。
    • initial temperature を受け取る new constructor
    • current temperature を returns する temperature getter
    • 10 と 30 の between (inclusive) の values のみを受け入れる set_temperature setter。この range の outside の value の場合、temperature は unchanged のままにします。
  • 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: 25

3つの 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}"
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rustオンラインコンパイラ