首先,我想说这个问题与使用
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
是有约束的生命周期参数。
所以,问题在于我们实现的函数 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
如果Rust最终支持
高种类类型,那么可能会有一种更优雅的解决问题的方法。
apply
和second
- 我正在尝试解决HRTBs问题。 - iopq