Rust 指定防锈剂的使用寿命
当我发现这是一个终生的问题时,我正在制造执行器/反应堆。它与async/Future无关,可以在没有async sugar的情况下复制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
使用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`