ミュータブルなメソッド
CoddyのRustジャーニー「Object Oriented Programming」セクションの一部 — レッスン 3/61。
時には、メソッドは単にデータを読み取るだけでなく、データを変更する必要がある場合があります。構造体のフィールドを変更できるメソッドを作成するには、&self の代わりに &mut self を使用します。
mutキーワードは可変の借用を示し、メソッドにインスタンスの内部状態を変更する許可を与えます:
struct Counter {
value: i32,
}
impl Counter {
fn increment(&mut self) {
self.value += 1;
}
fn decrement(&mut self) {
self.value -= 1;
}
fn get(&self) -> i32 {
self.value
}
}
increment と decrement は value を変更するため &mut self を使用し、一方で get はデータを読み取るだけなので &self を使用していることに注目してください。
ミュータブル(可変)なメソッドを呼び出す際、インスタンス自体もミュータブルとして宣言されている必要があります。
fn main() {
let mut counter = Counter { value: 0 };
counter.increment();
counter.increment();
println!("{}", counter.get()); // 2
counter.decrement();
println!("{}", counter.get()); // 1
}
インスタンスを作成する際にmutキーワードを忘れると、Rustはそのインスタンスに対して&mut selfメソッドを呼び出すことを禁止します。これにより、データが変更される可能性があることを常に意識できるようになります。
チャレンジ
簡単単一のフィールド balance (i32) を持つ BankAccount 構造体を作成してください。
BankAccount に対して、以下の3つのメソッドを持つ実装ブロックを追加してください:
deposit—&mut selfとamount: i32を受け取り、残高(balance)にその金額を加算します。withdraw—&mut selfとamount: i32を受け取り、残高(balance)からその金額を減算します。get_balance—&selfを受け取り、現在の残高をi32として返します。
3つの入力を受け取ります:
- 1行目:初期残高 (i32)
- 2行目:預金額 (i32)
- 3行目:引き出し額 (i32)
初期残高を使用して BankAccount の可変インスタンスを作成し、指定された金額を預け入れ(deposit)、指定された金額を引き出し(withdraw)、最終的な残高を表示してください。
期待される出力形式:
{final_balance}チートシート
構造体のフィールドを変更するメソッドは &mut self(可変の借用)を使用し、データを読み取るだけのメソッドは &self を使用します:
struct Counter {
value: i32,
}
impl Counter {
fn increment(&mut self) {
self.value += 1;
}
fn decrement(&mut self) {
self.value -= 1;
}
fn get(&self) -> i32 {
self.value
}
}
可変メソッドを呼び出すには、インスタンスを let mut で可変として宣言する必要があります:
let mut counter = Counter { value: 0 };
counter.increment();
counter.increment();
println!("{}", counter.get()); // 2
counter.decrement();
println!("{}", counter.get()); // 1
インスタンスに mut キーワードがない場合、Rust は &mut self メソッドの呼び出しを禁止します。
自分で試してみよう
use std::io;
// TODO: ここで BankAccount 構造体を定義します
// TODO: deposit、withdraw、get_balance メソッドを持つ BankAccount の実装ブロックを追加します
fn main() {
let mut input = String::new();
// 初回残高を読み込む
io::stdin().read_line(&mut input).expect("Failed to read line");
let initial_balance: i32 = input.trim().parse().expect("Invalid number");
input.clear();
// 入金額を読み込む
io::stdin().read_line(&mut input).expect("Failed to read line");
let deposit_amount: i32 = input.trim().parse().expect("Invalid number");
input.clear();
// 出金額を読み込む
io::stdin().read_line(&mut input).expect("Failed to read line");
let withdraw_amount: i32 = input.trim().parse().expect("Invalid number");
// TODO: initial_balance を使用して、ミュータブルな BankAccount インスタンスを作成します
// TODO: deposit_amount を引数に deposit を呼び出します
// TODO: withdraw_amount を引数に withdraw を呼び出します
// TODO: get_balance を使用して最終残高を表示します
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。