Rust言語のジェネリック関数(generic function)では、トレイト(trait)を用いて型パラメータ(parameterized types)の制約(bounds)を表現できる。これには2種類の記述方式が存在するが、where節でのみ表現可能な型制約がある。
下記のように、ジェネリック関数の型パラメータ(T
とU
)に対する直接的な制約ならば、いずれの記述方式を用いても等価。単に好みや可読性の高い方を選択すればよい。
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
The Rust Programming Language - Traitswhere
clauses: they allow bounds where the left-hand side is an arbitrary type (i32
in this case), not just a plain type parameter (likeT
).
関連URL