热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何在特征中定义异步方法?

我有一个特征,我用它来抽象tokio::net::TcpStream和tokio::net::UnixStream:

我有一个特征,我用它来抽象tokio::net::TcpStreamtokio::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;
}
impl TryRead for TcpStream {
fn do_try_read(&self, buf: &mut [u8]) -> Result {
self.try_read(buf)
}
}

问题是我想pub async fn readable(&self) -> io::Result<()>在这两种方法中都抽象出来,但是无法在特征中实现异步方法。我该如何处理?

回答


目前,async fn不能用于特质。造成这种情况的原因有些复杂,但未来有计划取消此限制。你可以参考一下为什么traits中的async fn很难对问题进行更深入的分析。

关联类型

同时,您可以使用关联类型:

trait Readable {
type Output: Future>;
fn readable(&self) -> Self::Output;
}

具体的未来类型

实现此特征时,您可以使用任何实现 的类型Future,例如Ready来自标准库:

use std::future;
impl Readable for Reader {
type Output = future::Ready>; fn readable(&self) -> Self::Output {
future::ready(Ok(()))
}
}

动态未来类型

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>>>; fn readable(&self) -> Self::Output {
let fut = async {
do_stuff().await
};
Box::pin(fut)
}
}

请注意,使用这些特征方法将导致每个函数调用的堆分配和动态分派。对于绝大多数应用程序来说,这不是一个很大的成本,但需要考虑。

捕获参考

可能出现的一个问题是关联类型Output没有生命周期,因此无法捕获任何引用:

struct Reader(String);
impl Readable for Reader {
type Output = Pin>>>; fn readable(&self) -> Self::Output {
let fut = async move {
println!("{}", self.0);
Ok(())
};
Box::pin(fut)
}
}

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

稳定 Rust 上的关联类型不能有生命周期,因此您必须将输出限制为从 self 捕获的盒装未来才能实现:

trait Readable {
// note the anonymous lifetime ('_) that refers to &self
fn readable(&self) -> Pin> + '_>>;
}
impl Readable for Reader {
fn readable(&self) -> Pin> + '_>> {
let fut = async move {
println!("{}", self.0);
Ok(())
};
Box::pin(fut)
}
}

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
}
}

async-traitasync方法转换为返回的方法Pin + Send = '_>>,类似于我们之前写的,所以也应该考虑与上面相同的点。

为了避免Sendasynctrait 方法上放置绑定,您可以像#[async_trait(?Send)]在 trait 和 impl 块上一样调用异步 trait 宏。

不稳定的特性

如果你在夜间,故事会更好。您可以启用该type_alias_impl_trait功能并使用常规async/await语法而无需装箱:

#![feature(type_alias_impl_trait)]
trait Readable {
type Output: Future>;
fn readable(&self) -> Self::Output;
}
impl Readable for Reader {
type Output = impl Future>; fn readable(&self) -> Self::Output {
async { ... }
}
}

借用问题仍然适用于上述代码。但是,使用不稳定功能generic_associated_types,您可以Output在整个生命周期内进行泛型并捕获self

trait Readable {
type Output<'a>: Future>;
fn readable(&self) -> Self::Output<'_>;
}

前面的例子编译,零装箱!

struct Reader(String);
impl Readable for Reader {
type Output<'a> = impl Future> + 'a; fn readable(&self) -> Self::Output<'_> {
let fut = async move {
println!("{}", self.0); // we can capture self!
Ok(())
};
Box::pin(fut)
}
}






推荐阅读
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
author-avatar
爱娟一辈子-_709
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有