我有这个最小的例子:
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
, 并克隆它:您可以
Arc
在较少的地方使用,Box
并通过将回调包装在其自己的函数中并将其装箱来代替使用(如果您有需要使用的现有 API)。