💨

メモ: トレイト境界

2023/06/07に公開
fn apply<F>(f: F)
where
    F: FnOnce(),
{
    f();
}

上記のようなジェネリックな関数は関数名applyと引数の間にジェネリックパラメータFを指定する。Fって関数なんだからジェネリックである必要ないじゃんと思ったけど、Fの候補としては関数・クロージャ・メソッド・オブジェクトがあるのでジェネリックパラメータが必要らしい。Cみたいに関数ポインタを引数とする関数にすればいいってわけではない。

where F: FnOnce(), 部分はトレイト境界と呼ばれ、Fの制約を記述できる。

  1. Fn: クロージャや関数が不変の参照経由で呼び出し可能であることを要求します。
  2. FnMut: クロージャや関数が可変の参照経由で呼び出し可能であることを要求します。
  3. FnOnce: クロージャや関数が所有権を取得し、一度だけ呼び出し可能であることを要求します。
  4. AsRef<T>: ジェネリック型が T に AsRef で変換可能であることを要求します。
  5. AsMut<T>: ジェネリック型が T に AsMut で変換可能であることを要求します。
  6. Borrow<T>: ジェネリック型が T に Borrow で借用可能であることを要求します。
  7. BorrowMut<T>: ジェネリック型が T に BorrowMut で可変借用可能であることを要求します。
  8. Deref: ジェネリック型が Deref で参照外し可能であることを要求します。
  9. DerefMut: ジェネリック型が DerefMut で可変参照外し可能であることを要求します。
  10. Into<T>: ジェネリック型が T に Into で変換可能であることを要求します。
  11. From<T>: ジェネリック型が T から From で変換可能であることを要求します。

ジェネリックパラメータが関数じゃない場合のトレイト境界の記述パターンには下記のようなものがある。

  1. トレイトを直接指定する: where T: SomeTrait
    T 型が SomeTrait トレイトを実装していることを要求します。
  2. 複数のトレイトを指定する: where T: Trait1 + Trait2
    T 型が Trait1 と Trait2 の両方を実装していることを要求します。
  3. ジェネリックトレイトを指定する: where T: Iterator<Item = u32>
    T 型が Iterator トレイトを実装しており、その Item 関連型が u32 型であることを要求します。
  4. ライフタイムの指定: where T: 'static
    T 型が静的ライフタイムを持つことを要求します。
  5. サイズ制約の指定: where T: Sized
    T 型が静的サイズを持つことを要求します。

Discussion