下面的代码:
use tokio; // 1.7.1
use futures::future::Future;
use std::pin::Pin;
use futures::FutureExt;
use std::marker::PhantomData;
use std::marker::Send;
use std::sync::Arc;
use async_trait::async_trait;
struct Orchestrator {
worker: Box<dyn WorkerT<Box<dyn Fn(i32) -> Pin<Box<dyn Future<Output = i32> + Send>> + Send + Sync>> + Send + Sync>
}
impl Orchestrator {
async fn other_things(&self, num: i32) -> i32{
// Do some async stuff in here
num+1
}
async fn main_stuff(self: Arc<Self>) {
let func = |num: i32| {
let slf = self.clone();
async move {
slf.other_things(num).await
}.boxed()
};
self.worker.do_work(Box::new(func)).await;
}
}
#[async_trait]
trait WorkerT<F: Fn(i32) -> Pin<Box<dyn Future<Output = i32> + Send>> + Send + Sync> {
async fn do_work(& self, func: F);
}
struct Worker<F: Fn(i32) -> Pin<Box<dyn Future<Output = i32> + Send>> + Send + Sync> {
phantom: std::marker::PhantomData<F>
}
#[async_trait]
impl<F: Fn(i32) -> Pin<Box<dyn Future<Output = i32> + Send>> + Send + Sync> WorkerT<F> for Worker<F> {
async fn do_work(& self, func: F) {
for i in 0..5 {
func(i).await;
}
}
}
#[tokio::main]
async fn main() {
let orchestrator = Arc::new(Orchestrator { worker: Box::new(Worker { phantom: PhantomData }) });
orchestrator.main_stuff().await;
}
出现以下错误:
error[E0597]: `self` does not live long enough
--> src/main.rs:22:23
|
21 | let func = |num: i32| {
| ---------- value captured here
22 | let slf = self.clone();
| ^^^^ borrowed value does not live long enough
...
28 | self.worker.do_work(Box::new(func)).await;
| -------------- cast requires that `self` is borrowed for `'static`
29 | }
| - `self` dropped here while still borrowed
目前,由于dyn WorkerT...
的默认生存期为'static
,因此要求main_stuff
中self
的借用为'static
。我需要放宽worker
字段的生存期,但我不知道如何放宽。如果我将worker
更改为"Worker instead of
dyn WorkerT ..."类型,这将起作用,但我更愿意把它作为一种特质。
我试过向Orchestrator结构体添加一个生存期,然后将该生存期赋予worker字段,但它说我创建的生存期需要比"static"更长。
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=7f34fa394d706409942659f1d8ce36c0
2条答案
按热度按时间mzmfm0qo1#
在创建闭包之前,你需要克隆
Arc
,这样你就可以给闭包一个Arc
。你代码中的东西试图借用self
,这不会比闭包更有效。克隆Arc
解决了这个问题,因为闭包现在可以拥有自己的Arc
,指向相同的值。例如:
内部克隆仍然是必需的,以便
func
类型实现Fn
(否则,由于将捕获的变量移到将来,它将实现FnOnce
)。jgovgodb2#
溶液
解释
你正在传递一个闭包,它反过来创建
async
例程。首先,闭包it self是静态的,所以它必须拥有self的所有权。我们将self克隆到slf
,并向闭包添加move,因此闭包移动了它。然后我们每次都必须克隆slf,并在async例程退出闭包时让它拥有它。