デフォルト実装のオーバーライド
CoddyのRustジャーニー「Object Oriented Programming」セクションの一部 — レッスン 32/61。
デフォルトの実装は便利ですが、型によっては標準とは異なる振る舞いが必要になる場合があります。そのような場合は、implブロック内で独自の実装を提供することで、デフォルトをオーバーライドできます。
同じシグネチャでメソッドを定義するだけで、独自のロジックを含めることができます:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
Greet はデフォルトの greet メソッドを提供していますが、Robot はそれを独自のバージョンで完全に置き換えています。Robot に対して greet() を呼び出すと、Rust はカスタムの実装を使用します:
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. ユニット 42 オンライン。
これにより柔軟性が得られます。デフォルトの設定で問題ない型は何も記述する必要がなく、一方で特殊な動作が必要な型は、関心のあるメソッドだけをオーバーライドできます。トレイトは、実装するすべての型でそのメソッドが利用可能であることを引き続き保証します。
チャレンジ
簡単異なるアラートタイプがメッセージをカスタマイズできる通知システムを構築しましょう!デフォルトの実装を持つトレイトを作成し、ある型にはデフォルトを使用させ、別の型にはカスタム動作でそれをオーバーライドさせます。
コードは3つのファイルに分けて構成します:
notifiable.rs:"Alert: Something happened!"を返すデフォルト実装を持つnotify(&self) -> Stringメソッドを含む、パブリックなNotifiableトレイトを定義します。alerts.rs: トレイトを異なる方法で実装する2つのパブリックな構造体を作成します:GenericAlert— デフォルトの通知を使用するユニット構造体(空の impl ブロック)UrgentAlert— パブリックなmessageフィールド (String) を持ち、デフォルトをオーバーライドして"URGENT: {message}"({message}は保持しているメッセージ)を返す構造体
main.rs: モジュールをまとめ、両方の動作を実演します。提供された入力を使用してGenericAlertとUrgentAlertを作成し、それぞれの通知をプリントします。
ここでの重要なポイントは、GenericAlert はデフォルトから動作をそのまま継承し、UrgentAlert は自身の impl ブロックでメソッドを定義することで独自の特化したバージョンを提供するという点です。
出力は以下の形式に従う必要があります:
Alert: Something happened!
URGENT: {message}例えば、入力が Server is down! の場合:
Alert: Something happened!
URGENT: Server is down!入力として、緊急アラート用のメッセージを1つ受け取ります。
チートシート
独自の実装を impl ブロックで提供することで、デフォルトのトレイト実装をオーバーライドできます。
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unit 42 online.
カスタムの動作を必要としない型は、空の impl ブロックを使用してデフォルトの実装を受け入れることができます。一方で、特殊な動作を必要とする型は、同じシグネチャでメソッドを定義することで、特定のメソッドをオーバーライドできます。
自分で試してみよう
mod notifiable;
mod alerts;
use alerts::{GenericAlert, UrgentAlert};
use notifiable::Notifiable;
fn main() {
// 緊急アラートメッセージの入力を読み取る
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: GenericAlert インスタンスを作成する
// TODO: 入力されたメッセージを使用して UrgentAlert インスタンスを作成する
// TODO: GenericAlert からの通知を出力する
// TODO: UrgentAlert からの通知を出力する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。