我正在尝试编写一个特征,该特征将一个异步函数(fetch_dep_proxy()
)的句柄包装起来。有问题的异步函数在内部调用JavaScript(使用适当的wasm_bindgen属性)。
use async_trait::async_trait;
use std::future::Future;
async fn fetch_dep_proxy(name: &str) -> Option<String> {
Some("test".to_owned()) // in practice, this would call into JavaScript and convert the returned JsFuture into a Option<String>
}
#[async_trait(?Send)]
pub trait Fetcher<T> {
async fn fetch(&self, name: &str) -> Result<T, String>;
}
struct FetchedValue {
pub val: String,
}
struct SourceFetcher<F> {
pub raw_fetch: F,
}
#[async_trait(?Send)]
impl<
Fut: Future<Output = Option<String>>,
F: Fn(&str) -> Fut,
> Fetcher<FetchedValue> for SourceFetcher<F>
{
async fn fetch(
&self,
name: &str,
) -> Result<FetchedValue, String> {
let resp = (self.raw_fetch)(name).await;
unimplemented!(); // todo: convert it to FetchedValue...
}
}
fn main() {
let sf = SourceFetcher{raw_fetch: fetch_dep_proxy};
}
请注意,返回的未来不是Send
,因为从JavaScript返回的JsFuture
不是Send
。
但是,编译器抱怨以下错误:
error[E0309]: the parameter type `Fut` may not live long enough
--> src/main.rs:29:39
|
22 | Fut: Future<Output = Option<String>>,
| ---- help: consider adding an explicit lifetime bound...: `Fut: 'async_trait +`
...
29 | ) -> Result<FetchedValue, String> {
| _______________________________________^
30 | | unimplemented!();
31 | | }
| |_____^
|
note: ...so that the type `impl std::future::Future` will meet its required lifetime bounds
--> src/main.rs:29:39
|
29 | ) -> Result<FetchedValue, String> {
| _______________________________________^
30 | | unimplemented!();
31 | | }
| |_____^
特别是,这表明我需要在Fut
上有明确的生命周期约束。大概生存期'async_trait
可能是async_trait
宏的一部分,但是我认为我对生存期界限的理解更加根本。我似乎无法理解类型参数的生命周期界限。
Fut
通用参数的显式生存期意味着什么?毕竟,fetch_dep_proxy()
是一个非常普通的异步函数(不是闭包),因此应转换为(name: &str) -> impl Future<Option<String>>
。特别是,Future是按值返回的,因此(self.raw_fetch)(name)
是按值返回的,因此此impl Future<Option<String>>
的生存期将仅取决于它在fetch()
中的使用方式。但是很明显,这不是正在发生的事情,对于Future来说,需要终身限制。生命周期限制在这里实际上意味着什么?如何解决此问题?