ジェネリックメソッド
CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 25/61。
ジェネリック構造体は任意の型を保持できますが、そのデータを操作するメソッドがなければあまり役に立ちません。ジェネリック構造体のメソッドを定義するには、implブロックで特別な構文を使う必要があります。
重要なのは、impl自体にジェネリックパラメータを宣言することです。
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
Wrapper<T>の前にあるimpl<T>に注目してください。これにより、RustはTが実装ブロック全体のジェネリック型パラメーターであることを認識します。この宣言がないと、RustはTという具体的な型を探し、見つけられずに失敗します。
getメソッドは&Tを返します。これはラッパーが保持する型への参照です。Tが整数、文字列、その他のどのような型でも機能します。
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
ジェネリック型のTがコンパイル時にそれぞれの具象型に適応するため、同じメソッド定義が両方で機能します。
チャレンジ
簡単ジェネリックなコンテナにメソッドを追加しましょう!どの型の値も保持でき、その内容を操作するメソッドを提供するBox構造体(Rust標準のBoxとは別物です)を作成します。
コードを2つのファイルに分けて作成します。
mybox.rs:T型の非公開フィールドcontentsを持つ、MyBox<T>という名前の公開ジェネリック構造体を定義します。この構造体にメソッドを実装します。- 指定した値で新しい
MyBoxを作成する、new関連関数 - 内容への参照を返す
peekメソッド(&selfを使用) - 新しい値を受け取り、現在の内容と置き換える
replaceメソッド(&mut selfを使用)
- 指定した値で新しい
main.rs:モジュールを読み込み、異なる型でジェネリックメソッドが動作することを示します。ボックスを作成し、その内容を参照したり、値を置き換えたりして、メソッドの動作を確認します。
ジェネリック構造体にメソッドを実装するための重要な構文を覚えておきましょう。RustにTが実装ブロック全体のジェネリックパラメーターであると伝えるために、MyBox<T>の前にimpl<T>を記述する必要があります。
メインファイルでは、次のようにMyBoxの動作を示してください。
- 整数(1つ目の入力。
i32として解析)を使ってボックスを作成する - その内容を参照して値を出力する
- 内容を新しい整数(2つ目の入力。
i32として解析)に置き換える - 再度参照して、更新された値を表示する
- 文字列(3つ目の入力)を使って2つ目のボックスを作成する
- 文字列ボックスの内容を参照する
出力は次の形式にしてください。
Integer box contains: {value}
After replace: {value}
String box contains: {value}たとえば、入力が10、25、Rustの場合:
Integer box contains: 10
After replace: 25
String box contains: Rust3つの入力として、初期の整数、置き換える整数、文字列を受け取ります。
自分で試してみよう
mod mybox;
use mybox::MyBox;
fn main() {
// 入力を読み込む
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_int: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: 最初の整数を格納した MyBox を作成する
// TODO: 内容を確認して "Integer box contains: {value}" を出力する
// TODO: 内容を置き換え用の整数に置き換える
// TODO: 再度内容を確認して "After replace: {value}" を出力する
// TODO: 文字列の値を格納した2つ目の MyBox を作成する
// TODO: 文字列を格納したボックスの内容を確認して "String box contains: {value}" を出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rustオンラインコンパイラ