Menu
Coddy logo textTech

セッター

CoddyのRustジャーニー「Object Oriented Programming」セクションの一部 — レッスン 12/61。

ゲッターを使うと、外部のコードがプライベートなデータを読み取ることができます。しかし、そのデータを変更させる必要がある場合はどうすればよいでしょうか?そこで登場するのがセッターメソッドです。これは、プライベートなフィールドを制御された方法で変更するパブリックメソッドです。

基本的なセッターは、&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;
    }
}

ゲッターとは異なり、Rustのセッターは通常、データを変更することを明確に示すために set_ プレフィックスを使用します。&mut self パラメータは不可欠です。これにより、メソッドに構造体のフィールドを変更する権限が与えられます。

セッターの真の力はバリデーション(検証)にあります。単にどんな値でも受け入れるのではなく、ルールを強制することができます:

pub fn set_balance(&mut self, amount: f64) {
    if amount >= 0.0 {
        self.balance = amount;
    }
    // 負の値は暗黙的に無視されます
}

これでウォレットは自らを保護するようになりました。外部コードがどのような値を設定しようとしても、balance(残高)が負になることはありません。これがカプセル化の真髄です。struct(構造体)が自身の不変条件(invariants)を制御するため、外部コードがそれを無効な状態にすることは決してできません。

challenge icon

チャレンジ

簡単

データの妥当性を維持するために、セッターがどのようにルールを強制できるかを示すサーモスタットシステムを構築しましょう。このサーモスタットには、安全な範囲内でのみ調整可能な温度設定機能を持たせます。

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

  • thermostat.rs: プライベートな temperature フィールド (i32) を持つ Thermostat 構造体を定義します。構造体はパブリックにする必要がありますが、無効な値から保護するためにフィールドはプライベートのままにします。以下を実装してください:
    • 初期温度を受け取る new コンストラクタ
    • 現在の温度を返す temperature ゲッター
    • 10から30(両端を含む)の間の値のみを受け入れる set_temperature セッター。値がこの範囲外の場合、温度は変更されないようにします。
  • main.rs: サーモスタットモジュールを取り込み、サーモスタットを作成します。様々な温度の設定を試み、各試行後の結果をプリントすることで、セッターのバリデーションを実証してください。

セッターは無効な値を黙って無視する必要があります。エラーメッセージは表示せず、有効な範囲外の値を設定しようとした場合は、現在の温度をそのまま維持してください。

出力は以下の形式に従う必要があります:

Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}

例えば、温度 20 でサーモスタットを作成し、次に 25 (有効) に設定しようとし、その後に 50 (無効) に設定しようとした場合、出力は以下のようになります:

Initial: 20
After setting to 25: 25
After setting to 50: 25

入力として、初期温度、1回目の試行温度、2回目の試行温度の3つを受け取ります。

チートシート

セッターメソッドを使用すると、外部コードが制御された方法でプライベートフィールドを変更できるようになります。これらは、構造体のデータを変更する権限を得るために &mut self を受け取ります。

基本的なセッターの構文:

pub fn set_balance(&mut self, amount: f64) {
    self.balance = amount;
}

Rustのセッターは通常、データを変更することを明確に示すために set_ プレフィックスを使用します。

セッターは、ルールを強制しデータの整合性を維持するためのバリデーション(検証)を可能にします:

pub fn set_balance(&mut self, amount: f64) {
    if amount >= 0.0 {
        self.balance = amount;
    }
    // 無効な値は暗黙的に無視されます
}

これはカプセル化の実践です。構造体が自身の不変条件を制御し、外部コードが構造体を無効な状態にすることを防ぎます。

自分で試してみよう

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: 1つ目の温度の設定を試行し、結果を表示する
    // 形式: "After setting to {attempted_value}: {temperature}"

    // TODO: 2つ目の温度の設定を試行し、結果を表示する
    // 形式: "After setting to {attempted_value}: {temperature}"
}
quiz icon腕試し

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

Object Oriented Programmingのすべてのレッスン