2411rust,实现特征

server/2024/11/27 20:26:34/

原文

Rust2024中,impl Trait位置的默认工作方式有了变化.是为了简化impl Trait,以更好地匹配人们一般的需求.

还添加了一个灵活的语法,让你需要时可完全控制.

Rust2024开始,一直在更改,何时可在返回位置impl Trait隐藏类型中使用泛型参数的规则:

1,即对返回位置impl Trait隐藏类型,的新的默认值,可在域中用任意泛型参数,而不仅是(仅适合Rust2024)类型;
2,用来显式声明可用哪些类型一个语法(可在任意版本中使用).

新的显式语法"用约束":如,impl Trait+use<'x,T>表示允许隐藏类型使用'xT(但不能使用域内其他泛型参数).

背景:返回位置impl Trait

本篇涉及返回位置impl Trait,如以下示例:

fn process_data(data: &[Datum]
) -> impl Iterator<Item = ProcessedDatum> {data.iter().map(|datum| datum.process())
}

在此返回位置``使用->impl Iterator,表明该函数返回实际类型由编译器根据函数体确定的"某种迭代器".它叫做"隐藏类型",因为调用者无法确切地知道它是什么;

他们必须针对Iterator特征编码.但是,在生成代码时,编译器根据实际的精确类型生成代码,从而确保充分优化调用者.

尽管调用者不知道确切的类型,但确实需要知道它继续借用数据参数,这样可确保在迭代数据引用保持有效.

此外,调用者必须可无需查看函数体,仅根据类型签名来弄清楚它.

Rust当前规则是,返回位置impl Trait值只有在impl Trait自身中有引用的生命期时,才能使用引用.此例中,impl Iterator<Item = ProcessedDatum>引用生命期,因此抓数据非法的.

你可在玩耍地上亲眼看到它.

此时收到的错误消息(“隐藏类型抓生命期”)不是很直观,但它确实附带了如何修复它的有用建议:
帮助:要声明impl Iterator<Item = ProcessedDatum>
''_'时,你可添加显式''_'生命期约束

impl Iterator<Item = ProcessedDatum> + '_ {

此建议的显式版本,函数签名变为:

fn process_data<'d>(data: &'d [Datum]
) -> impl Iterator<Item = ProcessedDatum> + 'd {data.iter().map(|datum| datum.process())
}

在此版本中,在impl Trait类型中显式引用,'d数据的生命期,因此允许使用.即只要正在使用迭代器,就必须持续借用数据,即它(正确地)此例中标记错误:

let mut data: Vec<Datum> = vec![Datum::default()];
let iter = process_data(&data);
data.push(Datum::default()); //<-错误!
iter.next();

此设计的可用性问题

impl Trait中可用哪些泛型参数规则是在早期根据一组有限的示例确定的.随着时间,会注意到它们有许多问题.

1,不是正确的默认值

主要代码基(编译器和crates.io上的)的调查发现,绝大多数返回位置impl Trait值都要用生命期,因此默认不抓没用.

2,不够灵活

当前规则是返回位置impl Trait总是允许使用类型参数,有时如果它们出现在约束中,允许使用生命期参数.

如上,该默认值是错误的,因为大多数函数实际上确实想允许返回类型使用生命期参数:这至少有变通.
默认值也是错误的,因为某些函数想要显式声明它们不在返回类型使用类型参数,且现在无法覆盖它.

最初意图是类型别名impl Trait可解决该用例,但很麻烦.

3,难以解释

因为默认值错误的,所以用户经常遇见这些错误!添加编译器提示以建议+'_有用,但用户必须遵守不完全理解的提示并不是很好.

4,错误的建议

impl Trait添加+'_参数可能会很怪,但并不是很难.可惜,它一般是错误的注解,导致不必要的编译器错误,正确的修复很复杂,有时甚至不可能.考虑如下示例:

fn process<'c, T> {context: &'c Context,data: Vec<T>,
) -> impl Iterator<Item = ()> + 'c {data.into_iter().map(|datum| context.process(datum))
}

此处,处理函数用context.process来处理数据中的(T类型)每个元素.因为返回值使用环境,因此按+'c声明它.

在此真正目标是允许类型中,使用'c;写+'c实现该目标,因为现在在约束列表中有'c.但是,虽然编写+'c是使'c出现在约束中的方便方法,但也表明隐藏类型必须比'c更久.

该要求是不必要的,实际上会导致本例编译错误,在玩耍地上试一下.

5,与Rust的其他部分不一致

当前设计还与Rust其他部分不一致.

异步FN去糖

Rust定义异步fn来去糖返回->impl Future的普通fn.因此,你想像处理此函数:

async fn process(data: &Data) { .. }

…将(大致)去糖为:

fn process(data: &Data
) -> impl Future<Output = ()> {async move {..}
}

实际上,因为可用生命期的规则有问题,这不是实际的去糖.实际的去糖针对一个特殊的允许使用所有生命期impl Trait.

但是该形式的impl Trait并未向终端用户公开.

impl Trait中的特征

Rust2024设计

上述问题促使在Rust2024结合了两件事来用新的方法:

1,一个新的默认值,即返回位置impl Trait隐藏类型可用域中不仅是类型(仅适合Rust2024)的泛型参数;

2,一个显式声明可用哪些类型的语法.

新的显式语法"用约束":如,impl Trait+use<'x,T>表示允许隐藏类型使用'xT(但不能使用域内其他泛型参数).

现在默认可使用生命期

Rust2024中,默认是返回位置impl Trait值的隐藏类型使用域内无论是类型还是生命期泛型参数.

即在Rust2024中可很好编译这篇博文初始示例,设置玩耍地中的版本2024来试试:

fn process_data(data: &[Datum]
) -> impl Iterator<Item = ProcessedDatum> {data.iter().map(|datum| datum.process())
}

好!

impl Trait可包含一个use<>bound来精确指定使用的泛型类型和生命期

例外是,当函数仅接受读取值且不包含在返回值中的引用参数时.一个示例是下面的indices()函数:它接受一个&[T]类型的切片,但它唯一做的是读取长度,用它来创建一个迭代器.
返回值中不需要切片自身:

fn indices<'s, T>(slice: &'s [T],
) -> impl Iterator<Item = usize> {0 .. slice.len()
}

Rust2021中,该声明隐式地表示切片没有返回类型.但在Rust2024中,默认值恰恰相反.即像此调用者停止在Rust2024中编译,因为他们现在假设直到迭代完成,数据是借用的:

fn main() {let mut data = vec![1, 2, 3];let i = indices(&data);data.push(4); //<-错误!<--假设访问`'&data'`i.next(); //
}

这实际上可能就是你想要的!即你可稍后修改indices()的定义,这样它实际上在结果中包含切片.即,新的默认值延续了impl Trait的传统,即保留在不中断调用者时,函数更改其实现灵活性.

但是,如果它不是你想要的呢?如果想保证indices()不会在其返回值中,保存参数切片的引用,你现在在返回类型中包含use<>约束来显式表示返回类型中可包含哪些泛型参数来完成.

indices()时,返回类型实际上不使用泛型,因此最好写为use<>:

fn indices<'s, T>(slice: &'s [T],
) -> impl Iterator<Item = usize> + use<> {//-----返回类型不使用`''s'或'T'`0 .. slice.len()
}

这与早期版本中impl Trait的限制相应,它总是必须抓类型参数.此时,可如下,避免了编译错误,但仍比必要的更保守:

fn indices<T>(slice: &[T],
) -> impl Iterator<Item = usize> + use<T> {0 .. slice.len()
}

或:'静态约束.对完全不抓引用特例,也可用'静态绑定,如下(自己试一下):

fn indices<'s, T>(slice: &'s [T],
) -> impl Iterator<Item = usize> + 'static {//-------返回类型不会抓引用.0 .. slice.len()
}

"此时,静态约束很方便,特别是考虑到当前use<>约束的实现限制,但use<>约束总体上更灵活.

如,编译器有一个返回newtype索引I而不是usize索引的变量,因此它包含一个use<I>声明.


http://www.ppmy.cn/server/144506.html

相关文章

【大数据技术基础】 课程 第8章 数据仓库Hive的安装和使用 大数据基础编程、实验和案例教程(第2版)

第8章 数据仓库Hive的安装和使用 8.1 Hive的安装 8.1.1 下载安装文件 访问Hive官网&#xff08;http://www.apache.org/dyn/closer.cgi/hive/&#xff09;下载安装文件apache-hive-3.1.2-bin.tar.gz 下载完安装文件以后&#xff0c;需要对文件进行解压。按照Linux系统使用的…

(超级详细!!!)解决“com.mysql.jdbc.Driver is deprecated”警告:详解与优化

目录 引言 1. 问题分析 1.1 警告内容解析 1.2 产生原因 2. 解决方案 2.1 更新驱动类 2.2 更新 JDBC URL 2.3 升级 MySQL Connector/J 依赖 2.4 清理缓存和重建项目 3. 示例代码 4. 注意事项 总结 引言 在使用 MySQL 数据库时&#xff0c;许多开发者会遇到以下警告&…

生成式语言模型 三范式 预训练、微调、强化反馈学习

ChatGPT 是一种典型的大语言模型&#xff0c;其训练过程可以分为预训练、微调和**强化学习&#xff08;RLHF&#xff09;**这三个主要阶段。以下是对这些阶段的详细讲解&#xff1a; 1. 预训练&#xff08;Pretraining&#xff09; 目标&#xff1a;让模型掌握基本的语言理解与…

用nextjs开发时遇到的问题

这几天已经基本把node后端的接口全部写完了&#xff0c;在前端开发时考虑时博客视频类型&#xff0c;考虑了ssr&#xff0c;于是选用了nextJs&#xff0c;用的是nextUi,tailwincss,目前碰到两个比较难受的事情。 1.nextUI个别组件无法在服务器段渲染 目前简单的解决方法&…

自动驾驶系列—告别眩光烦恼:智能大灯如何守护夜间行车安全

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

企业OA管理系统:Spring Boot技术实践与案例分析

3系统分析 3.1可行性分析 通过对本企业OA管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本企业OA管理系统采用SSM框架&#xff0c;JAVA作为开发语言&a…

如何给 Apache 新站点目录配置 SELinux ?

在 web 服务器管理领域&#xff0c;确保服务器环境的安全性至关重要。SELinux (Security-Enhanced Linux) 是保护 Linux 服务器最有效的工具之一&#xff0c;它是一种强制访问控制 (MAC mandatory access control) 安全机制。当使用最流行的 web 服务器 Apache 提供 web 内容时…

算法的时间复杂度

1.算法的复杂度 算法在编写为可执行程序后&#xff0c;运行需要耗费时间资源和空间资源。所以衡量一个算法的好坏&#xff0c;一般都是从时间和空间两个维度来衡量的。 而时间复杂度主要是衡量算法的运行快慢的&#xff0c;空间复杂度则是衡量算法运行所需的空间。 所以本篇文章…