use std::{future::Future, pin::Pin, thread::JoinHandle, fmt::Debug};
use tokio::runtime::Runtime;
struct Callback<E> {
f: Box<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>,
}
trait Provider {
fn setup(&self) -> JoinHandle<()>;
}
enum Foo {
A,
B
}
trait IntoFoo {
fn into_foo(&self) -> Foo;
}
impl<E: Debug + IntoFoo> Provider for Callback<E> {
fn setup(&self) -> JoinHandle<()> {
std::thread::spawn(move || {
// Running async function sycnhronously within another thread.
let rt = Runtime::new().unwrap();
rt.block_on(handle(Box::new(move || (self.f)())))
.expect("request loop failed")
})
}
}
async fn handle<E: Debug + IntoFoo + 'static>( callback_fn: Box<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>) -> Result<(), E> {
perform(Box::new(move || (callback_fn)())).await
}
pub async fn perform<
E: Debug + IntoFoo>(
op: Box<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>,
) -> Result<(), E> {
(op)().await
}
这是一些真实代码的简化版本,我基本上必须在结构内部传递异步回调。该回调通过多个函数传递。其中之一在新生成的线程中调用该函数。当调用
handle
时,我得到的错误出现在线程生成代码中。错误是:
error: lifetime may not live long enough
--> src/indexer/callback.rs:41:41
|
27 | fn bootstrap(&self, input: StageReceiver) -> BootstrapResult {
| - let's call the lifetime of this reference `'1`
...
41 | rt.block_on(handle_event(input, Box::new(move |ev: &Event| (self.f)(ev)), &retry_policy, utils))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
我应该如何安排这个?愿意更改结构字段类型和任何类似的内容。但我必须注意:这个函数必须能够被多次调用(它可能位于handle
中的循环内)。其他一些线程建议在 Box 中传递异步回调,其结果是固定的装箱特征对象。这就是我尝试这个系统的原因。
'static
&self
引用。一种选择是使用
Arc
而不是
Box
,然后克隆它:
use std::{fmt::Debug, future::Future, pin::Pin, sync::Arc, thread::JoinHandle};
use tokio::runtime::Runtime;
struct Callback<E> {
f: Arc<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>,
}
trait Provider {
fn setup(&self) -> JoinHandle<()>;
}
enum Foo {
A,
B,
}
trait IntoFoo {
fn into_foo(&self) -> Foo;
}
impl<E: Debug + IntoFoo + 'static> Provider for Callback<E> {
fn setup(&self) -> JoinHandle<()> {
let f = Arc::clone(&self.f);
std::thread::spawn(move || {
// Running async function sycnhronously within another thread.
let rt = Runtime::new().unwrap();
rt.block_on(handle(f)).expect("request loop failed")
})
}
}
async fn handle<E: Debug + IntoFoo + 'static>(
callback_fn: Arc<
dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync,
>,
) -> Result<(), E> {
perform(callback_fn).await
}
pub async fn perform<E: Debug + IntoFoo>(
op: Arc<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>,
) -> Result<(), E> {
op().await
}
您可以在较少的地方使用 Arc
,并通过将回调包装在其自己的函数中并将其框起来,使用
Box
代替(如果您有需要使用的现有 API)。