Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

Rust辞典

  1. トップページ
  2. Rust辞典
  3. ジェネリクスとトレイト境界の組み合わせ

ジェネリクスとトレイト境界の組み合わせ

トレイト境界は、ジェネリクスの型パラメータが満たすべき条件をトレイトで指定する仕組みで、型が特定のメソッドや操作を持つことをコンパイル時に保証します。

構文
// 基本的なトレイト境界(: の後にトレイト名)
fn 関数名<T: トレイト名>(引数: T) { ... }

// 複数のトレイトを要求する(+ で結合)
fn 関数名<T: Clone + Debug>(引数: T) { ... }

// where句による記述(複雑な境界をすっきり書ける)
fn 関数名<T, U>(a: T, b: U)
where
    T: Clone + Debug,
    U: Display + PartialOrd,
{ ... }

// impl Trait 構文(引数・戻り値で使える省略形)
fn 関数名(引数: impl トレイト名) -> impl トレイト名 { ... }
構文一覧
記法概要
<T: Trait>型パラメータTにトレイト境界を指定します。
<T: A + B>複数のトレイトを同時に要求します。
where T: Traitwhere句で境界を別行に書きます。複雑な条件を読みやすくできます。
impl Trait引数・戻り値の型として使える省略記法です。匿名の型パラメータと同等です。
dyn Trait動的ディスパッチ(トレイトオブジェクト)です。実行時にメソッドを解決します。
サンプルコード
use std::fmt::{Debug, Display};

// 複数トレイト境界:Clone と Debug を両方要求します。
fn print_twice<T: Clone + Debug>(item: T) {
    let copy = item.clone();
    println!("{:?} / {:?}", item, copy);
}

// where句:引数が2つ以上のときに可読性が高まります。
fn compare_and_show<T, U>(a: T, b: U) -> String
where
    T: Display + PartialOrd,
    U: Display,
{
    format!("a={}, b={}", a, b)
}

// impl Trait 構文:戻り値にトレイトを実装した型を返します。
fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

fn main() {
    print_twice(vec![1, 2, 3]); // [1, 2, 3] / [1, 2, 3]

    let result = compare_and_show(42, "hello");
    println!("{}", result); // a=42, b=hello

    let add5 = make_adder(5);
    println!("{}", add5(10)); // 15
}
概要

トレイト境界を使うことで、ジェネリクスの型パラメータに対して「このメソッドが使える」ことをコンパイル時に保証できます。境界を満たさない型を渡すとコンパイルエラーになるため、実行時エラーを防ぐことができます。

境界の数が多くなると関数シグネチャが読みにくくなるため、その場合は『where』句を使って別行に整理するのが一般的なスタイルです。

『impl Trait』を戻り値に使う場合、返す型は1種類に固定されます。条件によって異なるトレイト実装型を返したい場合は、『Box<dyn Trait>』(動的ディスパッチ)を使用してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。