我在制作执行器/反应器时发现这是一个终身问题。它与 async/Future 无关,并且可以在没有异步糖的情况下重现。
use std::future::Future;
struct Runtime;
fn start_with_runtime<C, F>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> F,
F: Future
{
let rt = Runtime;
let _future = closure(&rt);
// block_on(future);
}
async fn async_main(_rt: &Runtime) {
// I can use _rt to do async stuff here
}
fn main() {
start_with_runtime(|rt| { async_main(rt) });
}
我愿意start_with_runtime()
运行 future 并提供异步运行时引用作为参数。
它不编译:
error: lifetime may not live long enough
--> src/main.rs:17:31
|
17 | start_with_runtime(|rt| { async_main(rt) });
| --- ^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is impl std::future::Future
| has type `&'1 Runtime`
我认为这个问题似乎是因为 Rust 如何推断闭包的生命周期:
https://github.com/rust-lang/rust/issues/58052 https://github.com/rust-lang/rust/issues/58052 :
fn main() {
let f = |x: &i32| x;
let i = &3;
let j = f(i);
}
也不编译:
error: lifetime may not live long enough
--> src/main.rs:2:23
|
2 | let f = |x: &i32| x;
| - - ^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 i32
| let's call the lifetime of this reference `'1`
看起来我的关闭签名推断为|&'a Runtime| -> impl Future + 'b
从而产生生命周期错误。我觉得给出正确的预期关闭签名会有所帮助,但是我如何提供正确的签名start_with_runtime
?
fn start_with_runtime<C>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> (impl Future + 'a),
不起作用,因为impl Trait
这里不允许。
fn start_with_runtime<C,F>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> F,
F: Future + 'a
效果不太好,因为'a
HRTB 表达之外未知。
如果我知道类型,它就有效:
struct MyType<'a> {
_rt: &'a Runtime
}
fn start_with_runtime<C>(closure: C)
where
C: for<'a> FnOnce(&'a Runtime) -> MyType<'a>,
当你思考了所有的生生世世时,这有点悲伤,但语言无法提供表达这一点的方式。也许 Rust 中有一个技巧可以让这个工作正常进行?