yohhoyの日記

技術的メモをしていきたい日記

where節でしか記述できない型制約

Rust言語のジェネリック関数(generic function)では、トレイト(trait)を用いて型パラメータ(parameterized types)の制約(bounds)を表現できる。これには2種類の記述方式が存在するが、where節でのみ表現可能な型制約がある。

下記のように、ジェネリック関数の型パラメータ(TU)に対する直接的な制約ならば、いずれの記述方式を用いても等価。単に好みや可読性の高い方を選択すればよい。

trait X { }  // トレイトX
trait Y { }  // トレイトY

// 型パラメータへの直接記述
fn func<T: X, U: Y>(t: &T, u: &U)
{ /*...*/ }

// where節を用いた記法
fn func<T, U>(t: &T, u: &U) where T: X, U: Y
{ /*...*/ }

具体例をThe Rust Programming Language(https://doc.rust-lang.org/)より引用。ジェネリック関数inverseは型パラメータTを取り、ConvertToトレイトによりi32からTへ変換可能であること(where i32: ConvertTo<T>)を制約としている。これは型パラメータT自身の制約ではないため、where節でのみ記述可能である。

where is also more powerful than the simpler syntax. For example:

trait ConvertTo<Output> {
  fn convert(&self) -> Output;
}

impl ConvertTo<i64> for i32 {
  fn convert(&self) -> i64 { *self as i64 }
}

// can be called with T == i32
fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
  x.convert()
}

// can be called with T == i64
fn inverse<T>() -> T
    // this is using ConvertTo as if it were "ConvertFrom<i32>"
    where i32: ConvertTo<T> {
  42.convert()
}

This shows off the additional feature of where clauses: they allow bounds where the left-hand side is an arbitrary type (i32 in this case), not just a plain type parameter (like T).

The Rust Programming Language - Traits

関連URL