2017-07-30 70 views
2

我想写一个函数,它需要一个类型为Fn() ->()的闭包集合,即每个闭包都不带参数,不返回任何东西(我希望它们实际上是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。在每晚的Rust上,您可以将FnOnce更改为FnBox。否则,您可以使用FnMut或使用该问题的解决方法之一。还有另一个解决方法是基于定义一个额外的特征in the Rust book(参见清单20-20和清单20-21之间的部分)。

这里使用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()> 
    })); 
} 
相关问题