Menu
Coddy logo textTech

複数の境界

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

単一のトレイト境界では不十分な場合があります。both 印字でき、かつ要約を提供できるジェネリック型が必要になることもあります。Rust では、+ 構文を使って複数のトレイトを要求できます。

型が2つのトレイトを実装する必要があることを指定する方法は次のとおりです。

use std::fmt::Display;

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

fn announce<T: Display + Summary>(item: T) {
    println!("Breaking news: {}", item);
    println!("Summary: {}", item.summarize());
}

境界 T: Display + Summary は、「T が DisplaySummary のbothを実装しなければならない」という意味です。function 内では、両方のトレイトの機能を使用できます。たとえば、Display による {} を使った出力や、Summarysummarize() の呼び出しが可能です。

必要な数だけトレイトをチェーンできます。

fn process<T: Display + Summary + Clone>(item: T) {
    // 印刷、要約、およびクローンが可能
}

このパターンは、function が複数の振る舞いに依存する場合に不可欠です。any 型を受け入れて動作することを期待するのではなく、必要な capabilities を正確に明示し、コンパイラがコンパイル時にそれを強制します。

challenge icon

チャレンジ

簡単

複数の capabilities を持つことを必要とする product inspection system を構築しましょう!custom trait と standard trait の both を implements する型だけを受け入れる generic function を作成し、+ 構文によって複数の bounds を組み合わせる方法を示します。

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

  • product.rs: Inspectable という public trait を Define します。この trait には、&self を受け取り、inspection details を含む String を返す inspect という method があります。次に、public な Gadget struct を作成し、public な name (String) と serial (u32) の fields を持たせます。Gadget は InspectableInspecting: {name} を返す)と std::fmt::Display{name} (SN: {serial}) として format する)の both を implements する必要があります。最後に、DisplayInspectable の both を implements する any type T を受け入れる、full_report という public generic function を Create します。この function は 2 行を print します。first に {} formatter を使用して item を表示し、次に inspect() を calling した result を表示します。
  • main.rs: product module を取り込み、提供された inputs を使用して Gadget instance を Create します。gadget を使って full_report を Call し、both の trait requirements を満たしていることを示します。

複数の bounds の power は、full_report function が both の traits の capabilities を使用できることです。つまり、item をきれいに表示し、inspection details を取得できます。しかも、すべてが compile time に保証されます。

output には display format と inspection result の both が表示されます。

{name} (SN: {serial})
Inspecting: {name}

たとえば、inputs が Smartwatch98765 の場合:

Smartwatch (SN: 98765)
Inspecting: Smartwatch

2 つの inputs を受け取ります。gadget name と serial number です(u32 として parse します)。

自分で試してみよう

mod product;

use product::{Gadget, full_report};

fn main() {
    // 入力を読み取る
    let mut name = String::new();
    std::io::stdin().read_line(&mut name).expect("Failed to read line");
    let name = name.trim().to_string();
    
    let mut serial_input = String::new();
    std::io::stdin().read_line(&mut serial_input).expect("Failed to read line");
    let serial: u32 = serial_input.trim().parse().expect("Failed to parse serial");
    
    // TODO: name と serial で Gadget のインスタンスを作成する
    
    // TODO: あなたの gadget で full_report を呼び出す
}
quiz icon腕試し

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

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

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