iop*_*opq 10 closures rust trait-objects
我不能在不使用闭包的情况下编译它.我试图让函数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() {}
Run Code Online (Sandbox Code Playgroud)
我能做些什么来做我喜欢的apply工作?
Fra*_*gné 12
首先,让我说这个问题与impl Trait语法的使用无关.我将闭包转换为命名结构并获得相同的结果.
那么,让我们来看看你想要做的代码:
let f = apply(second, i);
let _ = tuples.iter().filter(f);
Run Code Online (Sandbox Code Playgroud)
编译器有什么说法呢?
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
Run Code Online (Sandbox Code Playgroud)
好的,所以我们有X型,它需要实现特性Y,但事实并非如此.但让我们仔细看看:
for<'r> impl
std::ops::FnMut<(&(_, _),)>:
std::ops::FnMut<(&'r &(_, _),)>
Run Code Online (Sandbox Code Playgroud)
啊哈!filter期望一个接受对元组引用的引用的函数,而我们传入的函数接受对元组的引用.filter传递对引用的引用,因为tuples.iter()迭代引用,并filter传递对引用的引用.
好吧,让我们改变second接受引用引用的定义:
fn second<'a, A, B: ?Sized>(&&(_, ref second): &&'a (A, B)) -> &'a B {
second
}
Run Code Online (Sandbox Code Playgroud)
编译器仍然不满意:
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
Run Code Online (Sandbox Code Playgroud)
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,
Run Code Online (Sandbox Code Playgroud)
在这里,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())
}
Run Code Online (Sandbox Code Playgroud)
或更明确的版本:
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())
}
Run Code Online (Sandbox Code Playgroud)
如果Rust最终支持更高级的类型,则可能有更优雅的方法来解决此问题.
| 归档时间: |
|
| 查看次数: |
2303 次 |
| 最近记录: |