Menu
Coddy logo textTech

トレイト境界の構文

CoddyのRustジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 40/61。

これまで、trait を定義し、struct に実装する方法を学びました。また、柔軟なコードを書くためにジェネリクスも扱いました。ここでは、これらの概念を組み合わせます。trait を使って、ジェネリック関数が受け入れられる型を制約する方法です。

パラメータに対して特定のmethodをcallする必要があるgeneric functionを考えてみましょう。何の制約もない場合、Rustは型 T がそのmethodを持つという保証を得られません。

fn print_info<T>(item: T) {
    println!("{}", item.summarize());  // エラー!T は summarize() を持っていないかもしれない
}

解決策はトレイト境界です。ジェネリックパラメーターの後に: TraitNameを追加することで、Tがそのトレイトを実装しなければならないことをRustに伝えます。

trait Summary {
    fn summarize(&self) -> String;
}

fn print_info<T: Summary>(item: T) {
    println!("{}", item.summarize());  // これでRustはこのメソッドが存在することを知っている
}

構文 <T: Summary> は、「T は Summary を実装する任意の型である」と読みます。これで、この関数は必要な動作を持つ型だけを受け入れるようになります。Summary を実装していない型を渡そうとすると、コンパイラーは明確なエラーを出して拒否します。

このパターンが強力なのは、特定の機能にもアクセスできる generic code を記述できるからです。あなたの function は柔軟性を保ち、any type で動作しますが、必要な振る舞いを提供する型に限られます。

challenge icon

チャレンジ

簡単

適切にフォーマットされたメッセージだけを送信できるよう、トレイト境界を使用する通知システムを構築しましょう!特定のトレイトを実装する任意の型を受け取る generic function を作成し、トレイト境界によってジェネリックパラメーターを制約する方法を示します。

コードを次の2つのファイルに整理します。

  • notification.rsmessageという名前のメソッドを持ち、&selfを受け取り、Stringを返す public Notifyトレイトを定義します。次に、このトレイトを実装する2つのpublic構造体を作成します。
    • Email:publicなsubjectフィールド(String)を持ちます。そのmessageメソッドはEmail: {subject}を返す必要があります。
    • SMS:publicなcontentフィールド(String)を持ちます。そのmessageメソッドはSMS: {content}を返す必要があります。
    最後に、Notifyトレイトを実装する任意の型Tを受け取る、send_notificationという名前のpublicな generic function を作成します。この function は、item に対してmessage()を calling した結果を表示する必要があります。
  • main.rs:notificationモジュールを取り込み、提供された inputs を使ってEmailSMSの両方の instance を作成します。それぞれに対してsend_notificationを Call し、Notifyを実装する任意の型で generic function が動作することを示します。

ここでの重要なポイントは、send_notificationが受け取る具体的な型を知らないということです。その型が message を生成できることだけを知っています。トレイト境界T: Notifyによって、この capability が保証されます。

Your output should show both notifications being sent:

Email: {subject}
SMS: {content}

For example, with inputs Meeting Tomorrow and On my way!:

Email: Meeting Tomorrow
SMS: On my way!

You will receive two inputs: the email subject and the SMS content.

自分で試してみよう

mod notification;

use notification::{Email, SMS, send_notification};

fn main() {
    // 入力を読み取る
    let mut subject = String::new();
    std::io::stdin().read_line(&mut subject).expect("Failed to read line");
    let subject = subject.trim().to_string();
    
    let mut content = String::new();
    std::io::stdin().read_line(&mut content).expect("Failed to read line");
    let content = content.trim().to_string();
    
    // TODO: subjectでEmailインスタンスを作成する
    
    // TODO: contentでSMSインスタンスを作成する
    
    // TODO: emailでsend_notificationを呼び出す
    
    // TODO: smsでsend_notificationを呼び出す
}
quiz icon腕試し

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

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rustオンラインコンパイラ