我有一个结构需要一个回调,该回调返回一个输出具有生命周期的未来:
struct Foo;
struct Bar;
struct Baz<F>
where F: for<'a> FnOnce(&'a Foo) -> impl std::future::Future<Output=&'a Bar> // ?
{
cb: F
}
Run Code Online (Sandbox Code Playgroud)
这不能编译,因为impl不能出现在特征边界中,所以出现语法错误:
Compiling playground v0.0.1 (/playground)
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/lib.rs:6:37
|
6 | where F: for<'a> FnOnce(&'a Foo) -> impl std::future::Future<Output=&'a Bar>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)
这也不能编译:
Compiling playground v0.0.1 (/playground)
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src/lib.rs:6:37
|
6 | where F: for<'a> FnOnce(&'a Foo) -> impl std::future::Future<Output=&'a Bar>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)
抱怨'a无法识别(和寿命'a,并'b会无关):
Compiling playground v0.0.1 (/playground)
error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
--> src/lib.rs:7:36
|
7 | O: for<'a> std::future::Future<Output=&'a Bar>,
| ^^^^^^^^^^^^^^
error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)
有没有办法指定这种关系?
它有点难看,但这是我能找到的最好的方法(用于struct Foo(Bar)演示):
use std::future::Future;
struct Bar;
struct Foo(Bar);
trait FooClosure<'a> {
type Fut: Future<Output = &'a Bar>;
fn call(self, foo: &'a Foo) -> Self::Fut;
}
impl<'a, Fut: Future<Output = &'a Bar>, C: FnOnce(&'a Foo) -> Fut> FooClosure<'a> for C {
type Fut = Fut;
fn call(self, foo: &'a Foo) -> Fut {
self(foo)
}
}
struct Baz<F: for<'a> FooClosure<'a>>(F);
fn main() {
let closure: Box<dyn for<'a> FnOnce(&'a Foo) -> futures::future::Ready<&'a Bar>> =
Box::new(|foo| futures::future::ready(&foo.0));
let baz = Baz(closure);
}
Run Code Online (Sandbox Code Playgroud)
我无法让编译器正确推断类型,因此我必须将闭包包装为盒装特征对象。从理论上讲,这应该是没有必要的,并且可能有办法避免这种情况,但我无法弄清楚。
注意:我认为有计划让你的原始代码无需这种黑魔法就能工作。