2411rust,异步函数

原文

Rust异步工作组很高兴宣布,在实现在特征中使用异步 fn目标方面取得了重大进度.将在下周发布稳定的Rust1.75版,会包括特征中支持impl Trait注解和async fn.

稳定化

自从RFC#1522Rust1.26中稳定下来以来,Rust就允许用户按函数的返回类型(一般叫"RPIT")编写impl Trait.

该函数返回"某种实现特征类型".这一般来返回闭包,迭代器其他复杂或无法显式编写的类型.

//给定一个玩家列表,返回在他们的`名字`上的`一个迭代器`.
fn player_names(players: &[Player]
) -> impl Iterator<Item = &String> {players.iter().map(|p| &p.name)
}

Rust1.75开始,你可在特征(RPITIT)定义和trait impl中使用返回位置impl Trait.如,你可用它来编写一个返回迭代器特征方法:

trait Container {fn items(&self) -> impl Iterator<Item = Widget>;
}
impl Container for MyContainer {fn items(&self) -> impl Iterator<Item = Widget> {self.items.iter().cloned()}
}

这一切与异步函数有什么关系呢?嗯,异步函数只是返回->impl Future的函数的"语法糖".因为在特征中,现在允许这些,还允许你编写使用async fn特征.

trait HttpService {async fn fetch(&self, url: Url) -> HtmlBody;
//^^^^^^^^变为:
//  fn fetch(&self, url: Url) -> impl Future<Output = HtmlBody>;
}

差距在哪?

公开特征中的->impl特征

仍不建议在公开特征API中普遍使用->impl Trait,因为用户无法对返回类型加限制.如,无法对容器特征通用的编写此函数:

fn print_in_reverse(container: impl Container) {for item in container.items().rev() {//错误:^^^对`'impl Iterator<Item=Widget>'`未实现`'DoubleEndedIterator'`特征eprintln!("{item}");}
}

尽管某些实现可能会返回实现DoubleEndedIterator迭代器,但在不定义另一个特征时,泛型代码无法利用它.

未来,打算为此添加一个解决方法.当前,->impl Trait最适合内部特征,或当你确信用户不需要额外约束时.否则,应该考虑使用关联类型.

公开特征中的异步函数

因为async fn解糖为->impl Future,因此有同样限制.事实上,如果今天在公开特征中使用空的异步fn,则会看到警告.
警告:不建议在公开特征中使用"async fn",因为无法指定自动特征约束.

异步用户特别感兴趣的是,在返回的未来上的发送约束.因为用户以后无法添加约束,因此错误消息说明你要选择:是否想你的特征多线程,窃取工作程序一起使用?

好的是,现在有个允许在公开特征中使用异步fn的方法!建议使用trait_variant::make过程宏来让你的用户选择.

过程宏是由rustlang组织发布的traitvariant包的一部分.在项目中加上cargo add trait-variant.使用:

#[trait_variant::make(HttpService: Send)]
pub trait LocalHttpService {async fn fetch(&self, url: Url) -> HtmlBody;
}

这创建两个版本特征:用LocalHttpService针对单线程执行器,HttpService针对多线程工作窃取执行器.因为后者更常用,因此此例中名字更短.
它有额外的发送约束:

pub trait HttpService: Send {fn fetch(&self,url: Url,) -> impl Future<Output = HtmlBody> + Send;
}

该宏适合异步,因为impl Future很少需要发送以外的额外约束,因此可成功为用户准备好.

动态分发

使用->impl Traitasyncfn特征不是对象安全的,即不支持动态分发.准备在未来推出的trait-variant包版本中启用动态分发.

未来如何改进

未来,希望允许用户添加自己的约束impl Trait返回类型,这样更普遍更有用.它还支持异步fn更高级用法.语法可能如下:

trait HttpService = LocalHttpService<fetch(): Send> + Send;

因为这些别名不需要特征作者的支持,因此,因此不需要异步特征发送变量.但是,这些变量仍会方便用户,因此期望大多数继续提供它们.

常见问题解答

是否可在特征中使用->impl Trait

私有特征,可自由使用->impl Trait.对公开特征,最好暂时避免使用它们,除非可预见到用户可能需要的所有约束(此时,你可用#[trait_variant::make],与异步一样).
期望取消来会此限制.

是否仍应使用#[async_trait]

你可能要继续使用异步特征原因有几个:
1,想支持低于1.75Rust版本.
2,你需要动态分发.

如上,希望在未来版本启用动态分发.

可在特征中使用async fn吗?有哪些限制

假设,你不用#[async_trait],则完全可以在特征中使用普通异步 fn.如果想支持多线程运行时,记住使用#[trait_variant::make].

最大限制类型必须总是决定实现了特征发送版本还是非发送版本.它不能在其泛型之一上有条件地实现发送版本.

这可在中间件模式中出现,如,如果T:HttpService,则为HttpServiceRequestLimitingService<T>.

为什么我需要#[trait_variant::make]Send约束

简单情况时,发现你的特征似乎与多线程程序配合得很好.但是,有些模式不管用.考虑以下:

fn spawn_task(service: impl HttpService + 'static) {tokio::spawn(async move {let url = Url::from("https://rustlang.org");let _body = service.fetch(url).await;});
}

如果特征上没有Send约束,则无法编译,并显示错误:"不能在线程间安全发送未来".用Send约束创建特征的变量,可避免发送用户此陷阱.

注意,如果未公开你的特征,则不会看到警告,因为如果有问题,总是可自行添加发送约束.

见此博客文章.

我可插件使用async fnimpl Trait

是的,你可以在特征实现中的async fn->implFuture拼写间自由切换.即使一个形式发送约束,因此.这样更易使用trait_variant创建的特征.

trait HttpService: Send {fn fetch(&self, url: Url)-> impl Future<Output = HtmlBody> + Send;
}
impl HttpService for MyService {async fn fetch(&self, url: Url) -> HtmlBody {//只要有`'do_fetch():Send'`就可以了!self.client.do_fetch(url).await.into_body()}
}

为什么这些签名不使用impl Future+'_

对特征中的->impl Trait,提前用了2024年的抓规则.即今天经常看到的+'_,在特征中是不必要的,因为已假设类型来抓输入生命期.

2024版中,此规则针对所有函数签名.

为什么在使用->impl Trait实现特征时收到"细化"警告

如果你的实现签名,包含比特征自身更详细的信息,你会收到警告:

pub trait Foo {fn foo(self) -> impl Debug;
}
impl Foo for u32 {fn foo(self) -> String {
//^^^^^^警告:`实现方法签名`中的`impl Trait`与`trait`方法签名不匹配self.to_string()}
}

原因是你可能泄露更多实现细节.如,如果以下代码编译.

fn main() {//实现者允许使用`'显示'`,还是只允许使用`特征`所说的`'调试'`println!("{}", 32.foo());
}

因为细化了特征实现,它确实可编译,但编译器会要求你在实现上使用#[allow(refining_impl_trait)],确认你打算细化特征接口.

注意,只能在可以命名类型时,才能使用关联类型.一旦impl_trait_in_assoc_type稳定下来,才取消此限制.

这是因为允许知识从未指定签名它们的项目中"泄漏"的auto trait泄漏.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL】MySQL数据库入门:构建你的数据基石

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL初阶探索&#xff1a;构建数据库基础 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f985;数据库基础&#x1f400;什么是数据库&#x1f40f;主流数据库&#x1f986;MySQL数据库的基本…

linux企业中常用NFS、ftp服务

1.静态ip配置 修改ip地址为静态vim /etc/sysconfig/network-scripts/ifcfg-enxxx BOOTPROTO"static" IPADDR192.168.73.10 GATEWAY192.168.73.2 # 该配置与虚拟机网关一致 NETMASK255.255.255.0重启网卡&#xff1a;systemctl restart network.service ping不通域名…

6.584-Lab1:MapReduce

前置知识/概念 Raft 是一个基于“Leader”的协议&#xff0c;能够保证分布式网路的一致性。 RPC&#xff08;Remote Producer Call&#xff09; 参考链接1 参考链接2 Go中RPC的简单实现 Golang中regexp正则表达式的用法 https://gukaifeng.cn/posts/golang-zheng-ze-biao-…

抽象java入门1.5.3.1——类的进阶

前言&#xff1a;在研究神技代码Hello word的时候&#xff0c;发现了一个重大公式bug&#xff0c;在代码溯源中&#xff0c;我发现了一个奇怪的东西&#xff0c;就是OUT不是类中类&#xff08;不是常规类的写法&#xff09; 内容总结&#xff1a; 代码运行的顺序复习 正片开始…

人力资源招聘系统的革新之路:从传统到智能的转变

在全球化与数字化交织的今天&#xff0c;企业间的竞争日益激烈&#xff0c;而人才作为企业发展的核心驱动力&#xff0c;其重要性不言而喻。传统的人力资源招聘方式&#xff0c;如依赖纸质简历、人工筛选、面对面面试等&#xff0c;不仅效率低下&#xff0c;且难以精准匹配企业…

Bootstrap和jQuery开发案例

目录 1. Bootstrap和jQuery简介及优势2. Bootstrap布局与组件示例&#xff1a;创建一个响应式的表单界面 3. jQuery核心操作与事件处理示例&#xff1a;使用jQuery为表单添加交互 4. Python后端实现及案例代码案例 1&#xff1a;用户登录系统Flask后端代码前端代码 5. 设计模式…

使用python-Spark使用的场景案例具体代码分析

使用场景 1. 数据批处理 • 日志分析&#xff1a;互联网公司每天会产生海量的服务器日志&#xff0c;如访问日志、应用程序日志等。Spark可以高效地读取这些日志文件&#xff0c;对数据进行清洗&#xff08;例如去除无效记录、解析日志格式&#xff09;、转换&#xff08;例如…

AXI DMA IP BUG踩坑记录

1. 问题描述 在突发的过程中总是一旦使用XAxiDma_SimpleTransfer函数就会出现AXI STREAM信号的READY信号先拉高4个数据(32位)的时钟后会迅速拉低,换句话说就是一旦PS端发起了XAxiDma_SimpleTransfer,AXI总线的READY信号就会拉高四个节拍,这样就会导致传输的数据出现问题。…

Vue2教程001:初识Vue

文章目录 1、初识Vue1.1、Vue2前言1.2、创建Vue实例1.3、插值表达式1.4 Vue响应式特性 1、初识Vue 1.1、Vue2前言 Vue是什么&#xff1f; 概念&#xff1a;Vue是一个用于构建用户界面的渐进式框架。 Vue的两种使用方式&#xff1a; Vue核心包开发 场景&#xff1a;局部模块…

【jvm】HotSpot中方法区的演进

目录 1. 说明2. JDK1.6及以前3. JDK1.74. JDK1.8及以后 1. 说明 1.在HotSpot虚拟机中&#xff0c;方法区&#xff08;Method Area&#xff09;的演进是一个重要的内存管理优化过程。2.从JDK1.6到JDK1.8&#xff0c;HotSpot虚拟机中的方法区经历了从永久代到元空间的重大变化。…

API 数据处理与 SQL 批量更新技巧:CASE 语句优化操作指南

前言 在现代应用程序开发中&#xff0c;数据处理和数据库操作是不可或缺的一部分。特别是在处理大量数据时&#xff0c;如何高效地更新数据库记录成为了关键问题。本文将对比两种常见的数据库更新方法&#xff1a;一种是使用 CASE 语句进行批量更新&#xff0c;另一种是通过循…

高级java每日一道面试题-2024年11月10日-框架篇[SpringBoot篇]-你对SpringBoot了解多少?

如果有遗漏,评论区告诉我进行补充 面试官: 你对SpringBoot了解多少? 我回答: 在Java高级面试中&#xff0c;SpringBoot是一个经常被提及的话题。以下是对SpringBoot的详细解析&#xff1a; SpringBoot概述 SpringBoot是Spring开源组织下的子项目&#xff0c;是Spring组件…

Linux dpkg命令详解

一、简介 dpkg 是基于 Debian 发行版 Linux 系统的低级包管理工具&#xff0c;可以手动安装、配置、移除 .deb 包&#xff0c;与 apt 命令不同的是&#xff0c;dpkg 不会自动处理包之间的依赖关系。 二、常用选项 安装包 sudo dpkg -i <package_name>.deb手动处理包依…

vscode vite+vue3项目启动调试

1、经常我们在普通的项目中&#xff0c;如果算法并不复杂&#xff0c;那么基本上console.log就可以搞定&#xff0c;当然也可以直接alert&#xff0c;打包的时候如果不去掉&#xff0c;还会在发版中上接弹出&#xff0c;给你个惊喜。 2、碰到了有些算法过程比较复杂的情况下&a…

如何给openshift 单节点集群配置hugepage

目前我有一台arm服务器, 是配置的单节点集群, 这个节点为是master, 也是worker. 理论上我应该用worker 标签给node 配置hugepage. 所以使用了以下方法: cat << EOF > hugepageconfig.yaml apiVersion: machineconfiguration.openshift.io/v1 kind: MachineCo…

Jdbc学习笔记(三)--PreparedStatement对象、sql攻击(安全问题)

目录 &#xff08;一&#xff09;使用PreparedStatement对象的原因&#xff1a; 使用Statement对象编写sql语句会遇到的问题 ​编辑 &#xff08;二&#xff09;sql攻击 1.什么是sql攻击 2.演示sql攻击 &#xff08;三&#xff09;防止SQL攻击 1.PreparedStatement是什么 …

java导出pdf

引入包 <properties><itext.version>8.0.5</itext.version></properties><dependencies><dependency><groupId>com.itextpdf</groupId><artifactId>itext-core</artifactId><version>${itext.version}</…

C/C++基础知识复习(23)

) 什么是 C 内联函数&#xff1f;它的作用是什么&#xff1f; C 内联函数&#xff08;inline function&#xff09; 是一种通过编译器优化的特殊函数。内联函数的主要作用是减少函数调用的开销&#xff0c;使得程序执行更加高效&#xff0c;尤其是对于那些频繁调用的函数。 当…

表单自动化填写-JavaScript脚本

一、场景 在日常工作、生活中常常会遇到需要填写、提交web表单的场景&#xff0c;往往涉及到了大量机械、重复的工作。作为程序员&#xff0c;我们崇尚消除重复、实现流程自动化、合理偷懒。 通过浏览器的控制台运行JavaScript脚本&#xff0c;可以简单的实现对web表单的填写…

后端分层解耦

引入 在上篇所举的例子中&#xff0c;我们将所有的代码均放在HelloControl方法之中&#xff0c;这样会导致代码的复用性、可读性较差&#xff0c;难以维护。因此我们需 三层架构 在之前的代码中&#xff0c;代码大体可以分为三部分&#xff1a;数据访问、数据逻辑处理、响应数…