型の匿名性
クロージャは、外側のスコープから変数を簡潔にキャプチャします。これには何か 影響があるのでしょうか?もちろんあります。クロージャを関数の パラメータとして使用するにはジェネリクスが必要になることに注目してください。これは、 クロージャの定義方法に起因して必要です。
#![allow(unused)] fn main() { // `F` はジェネリックでなければなりません。 fn apply<F>(f: F) where F: FnOnce() { f(); } }
クロージャが定義されると、コンパイラはキャプチャされた変数を内部に格納するための 新しい匿名構造体を暗黙的に作成し、その一方で、この未知の型に対して traits のいずれかである Fn、FnMut、または FnOnce によって機能を 実装します。この型は変数に割り当てられ、呼び出されるまで格納されます。
この新しい型は未知の型であるため、関数内で使用するにはすべて ジェネリクスが必要になります。しかし、境界のない型パラメータ <T> では依然として曖昧であり、 許可されません。したがって、それが実装している traits のいずれかである Fn、FnMut、または FnOnce によって境界を指定すれば、その型を指定するのに十分です。
// `F` は、入力を取らず何も返さないクロージャに対して // `Fn` を実装しなければなりません - これは `print` に必要なもの // そのものです。 fn apply<F>(f: F) where F: Fn() { f(); } fn main() { let x = 7; // `x` を匿名型にキャプチャし、それに対して `Fn` を // 実装します。それを `print` に格納します。 let print = || println!("{}", x); apply(print); }