2017-07-30 7 views
2

私は、タイプがFn() ->()のクロージャのコレクションを取る関数を書こうとしています。すなわち、それぞれのクロージャはargsを取りません。何も返しません(実際にはすべての環境をクロージャオブジェクトに移動するためにFnOnceにします) 。クロージャのコレクションを取得する関数を作成するにはどうすればよいですか?

私は多くのことを試しましたが(Box<Fn() ->()>を使用し、&'staticを使用しています)、私はこの動作を得ることができません。

Rust Playgroundに、私がしようとしていることを示すために要点を作成しました。

ここでは単純化されたコードです:

fn run_all_tests<I>(tests: I) 
where 
    I: IntoIterator<Item = Box<FnOnce() ->()>>, 
{ 
} 

fn main() { 
    let examples = [1, 2, 3]; 

    run_all_tests(examples.iter().map(
     |ex| Box::new(move |ex| assert!(ex > 0)), 
    )); 
} 

エラー:

error[E0271]: type mismatch resolving `<[[email protected]/main.rs:11:9: 11:49] as std::ops::FnOnce<(&{integer},)>>::Output == std::boxed::Box<std::ops::FnOnce() + 'static>` 
    --> src/main.rs:10:5 
    | 
10 |  run_all_tests(examples.iter().map(
    |  ^^^^^^^^^^^^^ expected closure, found trait std::ops::FnOnce 
    | 
    = note: expected type `std::boxed::Box<[[email protected]/main.rs:11:23: 11:48]>` 
       found type `std::boxed::Box<std::ops::FnOnce() + 'static>` 
    = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Map<std::slice::Iter<'_, {integer}>, [[email protected]/main.rs:11:9: 11:49]>` 
    = note: required by `run_all_tests` 

答えて

2

コードといくつかの問題があります。

  1. があなたの箱入りの閉鎖は、パラメータexを取りますが、しかし、形質FnOnce()はパラメータをとらない。パラメータexは、外側のクロージャからパラメータexをシャドウします。したがって、パラメータを取らない内部クロージャを意味すると仮定します:move || assert!(ex > 0)

  2. ex > 0のタイプの不一致は、非参照との比較のためです。パターンマッチングの際に、外閉鎖パラメータを逆参照して固定することができます:|&ex| ....

  3. 型推論はmapによって返されたイテレータはBox<FnOnce()>いうよりBox<unique closure object>かけなければならないことを発見するのに十分強力ではありません。コードがコンパイルされ、この時点でBox::new(move || assert!(ex > 0)) as Box<FnOnce()>

  4. ていますが、原因の言語の制限に箱入りのFnOnce()への呼び出しを追加するときには、コンパイルエラーになります:あなたはこの問題を解決するための明示的なキャストを追加することができます。 "cannot move a value of type FnOnce" when moving a boxed functionを参照してください。夜間の錆ではFnOnceFnBoxに変更できます。そうでない場合は、代わりにFnMutを使用するか、その問題の回避策を使用してください。 in the Rust book(リスト20-20とリスト20-21の間のセクションを参照)を指定して余分な特性を定義することに基づくもう1つの回避策があります。ここ

FnBoxを使用して固定コードである:

#![feature(fnbox)] 
use std::boxed::FnBox; 

fn run_all_tests<I>(tests: I) 
where 
    I: IntoIterator<Item = Box<FnBox()>>, 
{ 
    for t in tests { 
     t(); 
    } 
} 

fn main() { 
    let examples = [1, 2, 3]; 

    run_all_tests(examples.iter().map(|&ex| { 
     Box::new(move || assert!(ex > 0)) as Box<FnBox()> 
    })); 
} 
関連する問題