Rust 指定防锈剂的使用寿命

Rust 指定防锈剂的使用寿命,rust,closures,lifetime,Rust,Closures,Lifetime,当我发现这是一个终生的问题时,我正在制造执行器/反应堆。它与async/Future无关,可以在没有async sugar的情况下复制 使用std::future::future; 结构运行时; fn使用_运行时启动_(闭包:C) 哪里 C:对于F, F:未来 { 设rt=运行时; 让未来=结束(&rt); //封锁(未来); } async fn async\u main(\u rt:&Runtime){ //我可以在这里使用rt来做异步的事情 } fn main(){ 使用|运行时(| rt

当我发现这是一个终生的问题时,我正在制造执行器/反应堆。它与async/Future无关,可以在没有async sugar的情况下复制

使用std::future::future;
结构运行时;
fn使用_运行时启动_(闭包:C)
哪里
C:对于F,
F:未来
{
设rt=运行时;
让未来=结束(&rt);
//封锁(未来);
}
async fn async\u main(\u rt:&Runtime){
//我可以在这里使用rt来做异步的事情
}
fn main(){
使用|运行时(| rt |{async_main(rt)})启动|;
}
我希望
使用运行时()启动\u
以运行未来并提供异步运行时引用作为参数

它不编译:

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如何推断闭包的寿命:

:

fn main(){
设f=| x:&i32 | x;
设i=&3;
设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\u with_runtime
中提供正确的签名呢

fn使用_运行时启动_(闭包:C)
哪里
C:for(impl Future+a),
不工作,因为此处不允许使用
impl Trait

fn使用_运行时启动_(闭包:C)
哪里
C:对于F,
F:未来+a
不起作用,因为在HRTB表达式之外不知道
'a

如果我知道以下类型,它会起作用:



struct MyType MyType对不起,这是语言中的一个限制。只能指定具体类型的生存期。一种解决方法是使用trait对象类型

fn start_with_runtime<C, F, T>(closure: C)
where
    C: for<'a> FnOnce(&'a Runtime) -> Pin<Box<dyn Future<Item = T> + Send + 'a>>,
{
    let rt = Runtime;
    let _future = closure(&rt);
    // block_on(future); 
}
fn使用_运行时启动_(闭包:C)
哪里

C:对于Pin来说,这一个问题中似乎有两个不同的问题:所需的关系是否可以用Rust语法表示,以及它是否可以用于闭包类型推断

让我们从第一个开始。你是对的,这不能只用
where
子句来表达。要表达这一点,需要添加一个helper特征

trait following fn following fn for F
哪里
F:FnOnce(&'a Runtime)->Fu,
Fu:std::future::future+'a,
{
Fut型=Fu;
fn调用(self,rt:&'a Runtime)->Fu{
自我(rt)
}
}
()

好的,它可以用于异步函数,但是它是否可以用于需要类型推断的闭包?不幸的是,答案是“不”

错误:“借用fn”的实现不够通用
-->src/main.rs:33:5
|
5 |/trait借用fn`,对于任何生命期`'0`。。。

=注:…但是`[closure@src/main.rs:33:24:33:43]`实际实现了`借用fni take it你不能直接将
start\u with\u runtime
提取到main?因为这应该是可行的,没有任何明确的生命周期。
start\u with_runtime
应该放在板条箱中,由应用程序使用(例如,对应用程序隐藏运行时构造)。这是一种备份计划,应用程序可以
let rt=Runtime::new();rt.run(| rt | my_async_fn(rt))异步函数的返回类型。必须这样做,因为只要异步函数等待其他将来,参数就需要存储在将来。接收像
Rc
这样的共享指针而不是对运行时的引用对您有效吗?我想
Rc
会有效,但这是一种开销,我不喜欢一个正确的所有权模型。在本例中,关闭类似于
start_with_runtime(| rt |{Box::pin(async_main(rt))})所以这是一个可能的解决方法。然而,我发现Tanriol解决方案看起来更可取,因为它不需要堆和运行时多态性。看起来是非常聪明的方法!我认为这对我来说是一个很好的折衷(它不涉及堆,但要求FnOnce是一个函数,而不是闭包,这是可以的)。
error: implementation of `BorrowingFn` is not general enough
  --> src/main.rs:33:5
   |
5  | / trait BorrowingFn<'a> {
6  | |     type Fut: std::future::Future<Output = ()> + 'a;
7  | |     fn call(self, arg: &'a Runtime) -> Self::Fut;
8  | | }
   | |_- trait `BorrowingFn` defined here
...
33 |       start_with_runtime(|rt| async_main(rt)); // however, it does not work with closure type inference :-(
   |       ^^^^^^^^^^^^^^^^^^ implementation of `BorrowingFn` is not general enough
   |
   = note: `[closure@src/main.rs:33:24: 33:43]` must implement `BorrowingFn<'0>`, for any lifetime `'0`...
   = note: ...but `[closure@src/main.rs:33:24: 33:43]` actually implements `BorrowingFn<'1>`, for some specific lifetime `'1`