我刚开始使用rust的异步编程,遇到了一些奇怪的事情。我想在traits中引入异步而不需要装箱开销。我正在使用nightly和#![feature(type_alias_impl_trait)]
特性。
下面是最小化的代码:
#![feature(type_alias_impl_trait)]
use std::path::Path;
use std::future::Future;
type Error = Box<dyn std::error::Error>;
#[tokio::main]
async fn main() -> Result<(), Error> {
tokio::spawn(async move {
"test".to_owned().super_async("x").await
});
Ok(())
}
trait AsyncTrait {
type Fut<'a, P>: Future<Output=()>
where
Self: 'a,
P: AsRef<Path> + 'a;
fn test_async<P: AsRef<Path>>(&self, p: P) -> Self::Fut<'_, P>;
}
impl AsyncTrait for String {
type Fut<'a, P> = impl Future<Output = ()> + 'a
where
Self: 'a,
P: AsRef<Path> + 'a;
fn test_async<P: AsRef<Path>>(&self, p: P) -> Self::Fut<'_, P> {
async move {
let bs = p.as_ref();
()
}
}
}
trait SuperAsync: AsyncTrait {
type SuperFut<'a, P>: Future<Output=()>
where
P: AsRef<Path> + 'a,
Self: 'a;
fn super_async<P: AsRef<Path>>(&self, p: P) -> Self::SuperFut<'_, P>;
}
impl<T: AsyncTrait> SuperAsync for T {
type SuperFut<'a, P> = impl Future<Output = ()> + 'a
where
P: AsRef<Path> + 'a,
Self: 'a;
fn super_async<P: AsRef<Path>>(&self, p: P) -> Self::SuperFut<'_, P> {
async move {
self.test_async(p).await;
()
}
}
}
然后我得到了错误消息:
error: implementation of `AsRef` is not general enough
--> src/main.rs:45:5
|
45 | / tokio::spawn(async move {
46 | | "test".to_owned().super_async("x").await
47 | | });
| |______^ implementation of `AsRef` is not general enough
|
= note: `AsRef<Path>` would have to be implemented for the type `&'0 str`, for any lifetime `'0`...
= note: ...but `AsRef<Path>` is actually implemented for the type `&'1 str`, for some specific lifetime `'1`
我不明白错误消息。如果我删除tokio::spawn
或仅为String
实现SuperAsync
,则错误消失。需要帮助吗?
1条答案
按热度按时间42fyovps1#
我能够实现这一点:
我稍微修改了一下定义,现在生存期
'a
与self
和P
关联,同时将P
更改为引用,因此我们还可以将他的和AsRef
的生存期与'a
关联。通过将
P
修改为引用,我们强制我们不使用它,并且这个引用所指向的数据将比将来返回的数据生存更长时间。也许有一种方法可以接收一个拥有的P
值并确保它的生存期,但我不知道该方法。之所以添加
?Sized
,是因为P
解析为未调整大小的str
类型(而不是&str
)。