我有一个特征,我用它来抽象tokio::net::TcpStream和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)
}
}
Run Code Online (Sandbox Code Playgroud)
问题是我想pub async fn readable(&self) -> io::Result<()>在这两种方法中都抽象出来,但是无法在特征中实现异步方法。我该如何处理?
Ibr*_*med 10
目前,async fn不能用于特质。造成这种情况的原因有些复杂,但未来有计划取消此限制。你可以参考一下为什么traits中的async fn很难对问题进行更深入的分析。
同时,您可以使用关联类型:
trait Readable {
type Output: Future<Output = io::Result<()>>;
fn readable(&self) -> Self::Output;
}
Run Code Online (Sandbox Code Playgroud)
实现此特征时,您可以使用任何实现 的类型Future,例如Ready来自标准库:
use std::future;
impl Readable for Reader {
type Output = future::Ready<io::Result<()>>;
fn readable(&self) -> Self::Output {
future::ready(Ok(()))
}
}
Run Code Online (Sandbox Code Playgroud)
async函数返回一个 opaque impl Future,所以如果你需要调用一个,你没有一个具体的类型来设置Output。相反,您可以返回一个动态类型的Future:
impl Readable for Reader {
// or use the handy type alias from the futures crate:
// futures::BoxFuture<'static, io::Result<()>>
type Output = Pin<Box<dyn Future<Output = io::Result<()>>>>;
fn readable(&self) -> Self::Output {
let fut = async {
do_stuff().await
};
Box::pin(fut)
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,使用这些特征方法将导致每个函数调用的堆分配和动态分派。对于绝大多数应用程序来说,这不是一个很大的成本,但需要考虑。
可能出现的一个问题是关联类型Output没有生命周期,因此无法捕获任何引用:
struct Reader(String);
impl Readable for Reader {
type Output = Pin<Box<dyn Future<Output = io::Result<()>>>>;
fn readable(&self) -> Self::Output {
let fut = async move {
println!("{}", self.0);
Ok(())
};
Box::pin(fut)
}
}
Run Code Online (Sandbox Code Playgroud)
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> src/lib.rs:17:30
|
16 | fn readable(&self) -> Self::Output {
| ----- this data with an anonymous lifetime `'_`...
17 | let fut = async move {
| ______________________________^
18 | | println!("{}", self.0);
19 | | Ok(())
20 | | };
| |_________^ ...is captured here...
21 | Box::pin(fut)
| ------------- ...and is required to live as long as `'static` here
Run Code Online (Sandbox Code Playgroud)
稳定 Rust 上的关联类型不能有生命周期,因此您必须将输出限制为从 self 捕获的盒装未来才能实现:
trait Readable {
// note the anonymous lifetime ('_) that refers to &self
fn readable(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
}
impl Readable for Reader {
fn readable(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
let fut = async move {
println!("{}", self.0);
Ok(())
};
Box::pin(fut)
}
}
Run Code Online (Sandbox Code Playgroud)
async_trait为了避免这些样板文件,您可以使用async-trait板条箱:
#[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
}
}
Run Code Online (Sandbox Code Playgroud)
async-trait将async方法转换为返回的方法Pin<Box<dyn Future<Output = ...> + Send = '_>>,类似于我们之前写的,所以也应该考虑与上面相同的点。
为了避免Send在asynctrait 方法上放置绑定,您可以像#[async_trait(?Send)]在 trait 和 impl 块上一样调用异步 trait 宏。
如果你在夜间,故事会更好。您可以启用该type_alias_impl_trait功能并使用常规async/await语法而无需装箱:
#![feature(type_alias_impl_trait)]
trait Readable {
type Output: Future<Output = io::Result<()>>;
fn readable(&self) -> Self::Output;
}
impl Readable for Reader {
type Output = impl Future<Output = io::Result<()>>;
fn readable(&self) -> Self::Output {
async { ... }
}
}
Run Code Online (Sandbox Code Playgroud)
借用问题仍然适用于上述代码。但是,使用不稳定功能generic_associated_types,您可以Output在整个生命周期内进行泛型并捕获self:
trait Readable {
type Output<'a>: Future<Output = io::Result<()>>;
fn readable(&self) -> Self::Output<'_>;
}
Run Code Online (Sandbox Code Playgroud)
前面的例子编译,零装箱!
struct Reader(String);
impl Readable for Reader {
type Output<'a> = impl Future<Output = io::Result<()>> + 'a;
fn readable(&self) -> Self::Output<'_> {
let fut = async move {
println!("{}", self.0); // we can capture self!
Ok(())
};
Box::pin(fut)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1582 次 |
| 最近记录: |