如何在特征中定义异步方法? [英] How can I define an async method in a trait?
问题描述
我有一个特性,我用它来抽象 tokio::net::TcpStream
和 tokio::net::UnixStream
:
I have a trait that I'm using to abstract away tokio::net::TcpStream
and tokio::net::UnixStream
:
/// Interface for TcpStream and UnixStream.
trait TryRead {
// overlapping the name makes it hard to work with
fn do_try_read(&self, buf: &mut [u8]) -> Result<usize, std::io::Error>;
}
impl TryRead for TcpStream {
fn do_try_read(&self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
self.try_read(buf)
}
}
问题是我想抽象掉pub async fn readable(&self) ->io::Result<()>
在这两种方法中,但异步方法不能在特征中实现.我该如何处理?
The problem is that I want to abstract away pub async fn readable(&self) -> io::Result<()>
in both methods but async methods cannot be implemented in traits. How can I handle this?
推荐答案
目前,async fn
不能在 Trait 中使用.造成这种情况的原因有些复杂,但未来有计划取消此限制.你可以参考为什么特征中的异步 fn 很难深入分析问题.
Currently, async fn
cannot be used in traits. The reasons for this are somewhat complex, but there are plans to remove this restriction in the future. You can refer to why async fn in traits are hard for a deeper analysis of the problem.
同时,您可以使用关联类型:
In the meantime, you can use an associated type:
trait Readable {
type Output: Future<Output = io::Result<()>>;
fn readable(&self) -> Self::Output;
}
在实现这个特性时,你可以使用任何实现了 Future
的类型,比如 futures
crate 中的 Ready
:
When implementing this trait, you can use any type that implements Future
, such as Ready
from the futures
crate:
impl Readable for Reader {
type Output = future::Ready<io::Result<()>>;
fn readable(&self) -> Self::Output {
future::ready(Ok(()))
}
}
如果您无法静态输入结果,例如您正在调用 async
函数,您可以返回一个拥有的动态类型的 Future
:>
In cases where you can't statically type your result, such as if you are calling an async
function, you can return an owned dynamically typed Future
:
impl Readable for Reader {
type Output = Pin<Box<dyn Future<Output = io::Result<()>>>>;
fn readable(&self) -> Self::Output {
let fut = async {
do_stuff().await
};
Box::pin(fut)
}
}
请注意,使用这些 trait 方法将导致每个函数调用的堆分配和动态分派.对于绝大多数应用程序来说,这并不是一笔很大的开销,但在决定是否使用此功能时应予以考虑.
Note that using these trait methods will result in a heap allocation and dynamic dispatch per-function-call. This is not a significant cost for the vast majority of applications, but should be considered when deciding whether to use this functionality.
为了避免这些样板文件,您可以使用 async-trait
箱子:
To avoid some of this boilerplate, you can use the async-trait
crate:
#[async_trait]
trait Readable {
fn async readable(&self) -> io::Result<()>;
}
#[async_trait]
impl Readable for Reader {
async fn readable(&self) -> io::Result<()> {
do_stuff().await
}
}
async-trait
将 async
方法转换为返回 Pin<Box<dyn Future<Output = ...> 的方法.+ Send>>
,所以上面同样的点也应该考虑.
async-trait
transforms async
methods into methods that return Pin<Box<dyn Future<Output = ...> + Send>>
, so the same above points should be considered as well.
为了避免将 Send
绑定放在 async
trait 方法上,您可以调用异步 trait 宏作为 #[async_trait(?Send)]
在 trait 和 impl 块上.
To avoid having Send
bound placed on the async
trait methods, you can invoke the async trait macro as #[async_trait(?Send)]
on both the trait and the impl blocks.
这篇关于如何在特征中定义异步方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!