2017-07-30 38 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()> 
    })); 
} 
相關問題