トレイトの実装
CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 30/61。
trait の定義方法がわかったところで、次は struct にその契約を満たさせる方法を見てみましょう。trait を実装すると、抽象的な要件が具体的な動作に結び付きます。
構文では impl TraitName for StructName を使用します。
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
impl Speak for Dog ブロックは、Dog が Speak トレイトを実装していることを Rust に伝えます。その中で、実際のメソッド本体を記述します。ここで、犬がどのように話すかを定義します。
トレイトの力は、複数の型が同じトレイトを実装すると明確になります:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
Dog と Cat はどちらも Speak 機能を共有するようになりましたが、それぞれ独自の実装を提供します。どちらの型に対しても .speak() を呼び出せます。
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex says: ワン!
println!("{}", cat.speak()); // Whiskers says: ニャー!
これがRustにおけるポリモーフィズムの基盤です。異なる型、同じインターフェース、それぞれ固有の振る舞い。
チャレンジ
簡単異なる型にトレイトを実装して、トレイトを実際に活用してみましょう!Describableトレイトを作成し、それを2つの異なる構造体に実装します。それぞれが独自の説明を提供します。
コードを3つのファイルに分けて整理します。
describable.rs:publicなDescribableトレイトと、describe(&self) -> Stringメソッドを定義します。items.rs:トレイトを実装する2つのpublicな構造体を作成します。- publicな
titleフィールド(String)を持つBook - publicな
nameフィールド(String)を持つMovie
Describableを実装し、それぞれ独自の説明形式を持つようにします。- publicな
main.rs:モジュールをまとめ、両方の構造体のinstanceを作成し、それらのdescribeメソッドを呼び出して、同じトレイトが異なる型に対して異なる出力を生成する方法を示します。
BookはBook: {title}として自身を説明し、MovieはFilm: {name}として自身を説明するようにします。それぞれの型が同じ契約を満たしながら、独自の動作を持っていることに注目してください。
mainファイルで、提供された2つのinputsを使ってbookとmovieを作成し、それぞれの説明を別々の行に出力します。
出力は次の形式に従う必要があります。
Book: {title}
Film: {name}たとえば、inputsが1984とInceptionの場合:
Book: 1984
Film: Inception2つのinputs、つまりbookのtitleとmovieのnameを受け取ります。
自分で試してみよう
mod describable;
mod items;
use describable::Describable;
use items::{Book, Movie};
fn main() {
// 入力を読み取る
let mut title = String::new();
std::io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
// TODO: titleでBookインスタンスを作成する
// TODO: nameでMovieインスタンスを作成する
// TODO: bookの説明を出力する
// TODO: movieの説明を出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Rustオンラインコンパイラ