我正在尝试编写一个函数,它接受类型为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 `<[closure@src/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<[closure@src/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}>, [closure@src/main.rs:11:9: 11:49]>`
= note: required by `run_all_tests`
答案 0 :(得分:2)
代码有几个问题:
您的盒装闭包采用参数ex
,但特征FnOnce()
不带参数。参数ex
也会遮盖外部闭包中的参数ex
,所以我假设你的意思是内部闭包不带参数:move || assert!(ex > 0)
。
由于比较了对非引用的引用,因此ex > 0
中的类型不匹配。可以通过在模式匹配期间解除引用外部闭包参数来修复:|&ex| ....
类型推断不足以发现map
返回的迭代器应该超过Box<FnOnce()>
而不是Box<unique closure object>
。您可以添加明确的强制转换来解决此问题:Box::new(move || assert!(ex > 0)) as Box<FnOnce()>
此时,代码将进行编译,但由于语言限制,当您添加对装箱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()>
}));
}