如果不使用闭包,我无法编译它。我试图让函数 apply
首先返回正确类型的闭包。
#![feature(conservative_impl_trait)]
#![allow(dead_code)]
fn accumulate<'a>(tuples: &[(&'a str, &Fn(i32) -> bool)], i: i32) {
// this works
let _ = tuples.iter().filter(|t| apply(second, i)(t));
// this doesn't
//let f = apply(second, i);
//let _ = tuples.iter().filter(f);
//this works as well
let f = |t: &&(_,_)| apply(second, i)(t);
let _ = tuples.iter().filter(f);
}
fn apply<A, B, C, F, G>(mut f: F, a: A) -> impl FnMut(B) -> C
where F: FnMut(B) -> G,
G: FnMut(A) -> C,
A: Clone
{
move |b| f(b)(a.clone())
}
fn second<A, B: ?Sized>(&(_, ref second): &(A, B)) -> &B {
second
}
fn main() {}
我该怎么做才能让 apply
像我想要的那样工作?
最佳答案
首先,让我说这个问题与 impl Trait
的使用无关。句法。我将闭包转换为命名结构并获得了相同的结果。
那么,让我们看看您想要的代码:
let f = apply(second, i);
let _ = tuples.iter().filter(f);
编译器对此有何看法?
error[E0277]: the trait bound `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` is not satisfied
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ trait `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` not satisfied
error[E0277]: the trait bound `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnOnce<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` is not satisfied
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ trait `for<'r> impl std::ops::FnMut<(&(_, _),)>: std::ops::FnOnce<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` not satisfied
好的,所以我们有类型 X,它需要实现特征 Y,但它没有。但让我们仔细看看:
for<'r> impl
std::ops::FnMut<(&(_, _),)>:
std::ops::FnMut<(&'r &(_, _),)>
啊哈! filter
期望一个函数接受元组的对引用的引用,而我们传入的函数接受对元组的引用。 filter
将引用传递给引用,因为 tuples.iter()
遍历引用,filter
传递对这些的引用。
好吧,让我们改变second
的定义接受对引用的引用:
fn second<'a, A, B: ?Sized>(&&(_, ref second): &&'a (A, B)) -> &'a B {
second
}
编译器仍然不高兴:
error[E0277]: the trait bound `for<'r> impl std::ops::FnMut<(&&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` is not satisfied
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ trait `for<'r> impl std::ops::FnMut<(&&(_, _),)>: std::ops::FnMut<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>` not satisfied
error[E0271]: type mismatch resolving `for<'r> <impl std::ops::FnMut<(&&(_, _),)> as std::ops::FnOnce<(&'r &(&str, &std::ops::Fn(i32) -> bool),)>>::Output == bool`
--> <anon>:11:27
|
11 | let _ = tuples.iter().filter(f);
| ^^^^^^ expected bound lifetime parameter , found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#24r
expected bound lifetime parameter , found concrete lifetime
...这是什么意思?
f
的类型是某种实现 FnMut(&'c &'b (&'a str, &Fn(i32) -> bool)) -> bool
的类型.在调用 apply
, B == &'c &'b (&'a str, &Fn(i32) -> bool)
和 C == bool
.注意 B
这里是一个固定类型; 'c
表示一个固定的生命周期,称为具体生命周期。
我们来看看filter
的签名:
fn filter<P>(self, predicate: P) -> Filter<Self, P> where
Self: Sized, P: FnMut(&Self::Item) -> bool,
在这里,P
必须实现 FnMut(&Self::Item) -> bool
.实际上,此语法是 for<'r> FnMut(&'r Self::Item) -> bool
的简写.这里。 'r
是一个绑定(bind)的生命周期参数。
所以,问题是我们实现了 FnMut(&'c &'b (&'a str, &Fn(i32) -> bool)) -> bool
的函数不实现for<'r> FnMut(&'r Self::Item) -> bool
.我们需要一个实现 for<'c> FnMut(&'c &'b (&'a str, &Fn(i32) -> bool)) -> bool
的函数.目前唯一的方法是写 apply
像这样:
fn apply<A, B, C, F, G>(mut f: F, a: A) -> impl FnMut(&B) -> C
where F: FnMut(&B) -> G,
G: FnMut(A) -> C,
A: Clone
{
move |b| f(b)(a.clone())
}
或更明确的版本:
fn apply<A, B, C, F, G>(mut f: F, a: A) -> impl for<'r> FnMut(&'r B) -> C
where F: for<'r> FnMut(&'r B) -> G,
G: FnMut(A) -> C,
A: Clone
{
move |b| f(b)(a.clone())
}
如果 Rust 最终支持 higher-kinded types ,可能有更优雅的方法来解决这个问题。
关于rust - 返回闭包的函数在我的过滤器中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39541312/