Rust团队很高兴宣布一个新的Rust版本1.51.0。Rust是一种编程语言,它使每个人都可以构建可靠且高效的软件。
如果您通过rustup安装了旧版本的Rust,那么获取Rust 1.51.0就像下面这样简单:
rustup update stable
如果您还没有它,可以 从我们网站上的相应页面获取rustup
,然后在GitHub上查看1.51.0的 详细发行说明。
1.51.0稳定版中的内容
此版本代表了相当长一段时间以来Rust语言和Cargo的最大新增功能之一,稳定了const泛型的MVP和Cargo的新功能解析器。让我们开始吧!
Const Generics MVP
在此版本之前,Rust允许您在整个生命周期或类型中对类型进行参数化。例如,如果我们希望在struct
数组的元素类型上具有通用的,则可以编写以下代码:
struct FixedArray<T> {
// ^^^ Type generic definition
list: [T; 32]
// ^ Where we're using it.
}
如果再使用FixedArray<u8>
,编译器将使它成为单态版本FixedArray
,如下所示:
struct FixedArray<u8> {
list: [u8; 32]
}
这是一项强大的功能,可让您编写可重用的代码,而没有运行时的开销。但是,直到发布此版本之前,不可能轻易地对这些类型的值进行泛型。这在包含其长度的类型定义([T; N]
)中的数组中最为明显,以前您无法对其进行泛型。现在有了1.51.0,您可以编写对任何整数bool
,或char
类型的值通用的代码!(使用struct
或enum
值仍然不稳定。)
现在,此更改使我们可以拥有自己的数组结构,该数组结构在其类型和长度上是通用的。让我们看一个示例定义,以及如何使用它。
struct Array<T, const LENGTH: usize> {
// ^^^^^^^^^^^^^^^^^^^ Const generic definition.
list: [T; LENGTH]
// ^^^^^^ We use it here.
}
现在,如果再使用Array<u8, 32>
,编译器将使它变为单态版本Array
,如下所示:
struct Array<u8, 32> {
list: [u8; 32]
}
Const泛型为库设计人员添加了一个重要的新工具,可用于创建功能强大的新编译时安全API。如果您想了解有关const泛型的更多信息,还可以查看“ Const Generics MVP Hits Beta”博客文章,以获取有关该功能及其当前限制的更多信息。我们迫不及待想看看您创建了哪些新的库和API!
array::IntoIter
稳定化
作为const泛型稳定化的一部分,我们还正在稳定使用它的新API std::array::IntoIter
。IntoIter
允许您在任何数组上创建按值迭代器。以前,没有一种便捷的方法可以遍历数组的所有值,仅引用它们即可。
fn main() {
let array = [1, 2, 3, 4, 5];
// Previously
for item in array.iter().copied() {
println!("{}", item);
}
// Now
for item in std::array::IntoIter::new(array) {
println!("{}", item);
}
}
注意,这是作为一个单独的方法而不是.into_iter()
在数组上添加的,因为当前会引入一些破损。当前.into_iter()
引用切片按引用迭代器。我们正在探索将来使之更符合人体工程学的方法。
货运的新功能解析器
依赖管理是一个难题,它最难的部分之一就是选择当两个不同的程序包依赖哪个版本的依赖时。这不仅包括其版本号,还包括该软件包启用或未启用的功能。Cargo的默认行为是在依赖关系图中多次引用单个包时合并功能。
例如,假设您有一个foo
具有功能A和B的依赖项,该依赖项已由软件包bar
和使用baz
,但bar
依赖于foo+A
和baz
依赖于foo+B
。Cargo将合并这两个功能并将其编译foo
为foo+AB
。这样的好处是您只需要编译foo
一次,然后就可以为bar
和重复使用baz
。
但是,这也有不利的一面。如果在构建依赖性中启用的功能与要构建的目标不兼容怎么办?
生态系统中一个常见的例子是std
许多#![no_std]
板条箱中包含的可选功能,允许板条箱在std
可用时提供附加功能。现在,假设您要在二进制文件中使用的#![no_std]
版本,并在中使用构建时的。如果您的构建时间依赖项依赖于,那么您的二进制文件现在也还依赖于,这意味着它将不再编译,因为它不适用于您的目标平台。foo
#![no_std]
foo
build.rs
foo+std
foo+std
std
这一直是货运中的一个长期问题,在此版本resolver
中,您的中有一个新选项Cargo.toml
,您可以在其中设置resolver="2"
告诉货运尝试使用新方法来解析功能。您可以查看RFC 2957,以获得有关行为的详细说明,可以将其概述如下。
- 开发依赖项—当程序包作为常规依赖项和开发依赖项共享时,仅当当前构建包含开发依赖项时,才启用开发依赖项功能。
- 主机依赖关系—当程序包作为常规依赖关系和构建依赖关系或proc-macro共享时,用于常规依赖关系的功能将保持独立于构建依赖关系或proc-macro。
- 目标依赖项—当程序包在构建图中多次出现,并且其中一个实例是特定于目标的依赖项时,仅当当前正在构建目标时,才启用特定于目标的依赖项的功能。
尽管这可能导致某些板条箱不止一次被编译,但是在将特征与货物一起使用时,这应该提供更直观的开发体验。如果您想了解更多信息,还可以阅读《货运手册》中的“功能解析器”部分以获取更多信息。我们要感谢货运团队以及所有参与设计和实施新分解器的辛勤工作的人!
[package]
resolver = "2"
# Or if you're using a workspace
[workspace]
resolver = "2"
拆分调试信息
尽管在发行版中并不经常强调,但Rust团队一直在努力改善Rust的编译时间,而该发行版是macOS上Rust长期以来最大的改进之一。调试信息将二进制代码映射回您的源代码,以便该程序可以为您提供有关运行时出现问题的更多信息。在macOS中,以前.dSYM
使用名为的工具将调试信息收集到一个文件夹中,该工具dsymutil
可能会花费一些时间并占用大量磁盘空间。
将所有debuginfo收集到此目录中有助于在运行时查找它,尤其是在二进制文件正在移动的情况下。但是,这样做的缺点是,即使您对程序进行了很小的更改,dsymutil
也将需要在整个最终二进制.dSYM
文件上运行以产生最终文件夹。有时这可能会增加构建时间,尤其是对于大型项目,因为总是会收集所有依赖项,但这是必需的步骤,因为如果没有它,Rust的标准库将不知道如何在macOS上加载调试信息。
最近,Rust回溯切换到使用其他后端,该后端支持无需运行即可加载debuginfo dsymutil
,并且我们已稳定了对跳过dsymutil
运行的支持。这可以显着加快包含debuginfo的构建,并显着减少所使用的磁盘空间量。我们还没有运行广泛的基准测试,但是已经看到很多关于人们使用这种行为在macOS上构建速度更快的报告。
您可以通过-Csplit-debuginfo=unpacked
在运行时设置标志rustc
或在Cargo中将选项设置为来启用此新行为。“解压”选项指示rustc将.o对象文件保留在生成输出目录中,而不是删除它们,并跳过运行dsymutil的步骤。Rust的回溯支持足够聪明,足以知道如何查找这些.o文件。诸如lldb之类的工具也知道如何执行此操作。只要您不需要在保留调试信息的情况下将二进制文件移动到其他位置,这就应该起作用。split-debuginfo
[profile]
unpacked
[profile.dev]
split-debuginfo = "unpacked"
稳定的API
总体而言,此发行版稳定了18种针对诸如slice
和的各种类型的新方法的使用Peekable
。一个显着的增加是稳定ptr::addr_of!
和ptr::addr_of_mut!
,它允许您创建未对齐的领域原始指针。以前这是不可能的,因为Rust需要&/&mut
对齐并指向初始化的数据,&addr as *const _
然后由于&addr
需要对齐会导致未定义的行为。这两个宏现在使您可以安全地创建未对齐的指针。
use std::ptr;
#[repr(packed)]
struct Packed {
f1: u8,
f2: u16,
}
let packed = Packed { f1: 1, f2: 2 };
// `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior!
let raw_f2 = ptr::addr_of!(packed.f2);
assert_eq!(unsafe { raw_f2.read_unaligned() }, 2);
稳定了以下方法。
Arc::decrement_strong_count
Arc::increment_strong_count
Once::call_once_force
Peekable::next_if_eq
Peekable::next_if
Seek::stream_position
array::IntoIter
panic::panic_any
ptr::addr_of!
ptr::addr_of_mut!
slice::fill_with
slice::split_inclusive_mut
slice::split_inclusive
slice::strip_prefix
slice::strip_suffix
str::split_inclusive
sync::OnceState
task::Wake
其他变化
Rust 1.51.0发行版中还有其他更改:查看Rust,Cargo和Clippy中的更改。
1.51.0的贡献者
许多人一起创建了Rust 1.51.0。没有你们所有人,我们不可能做到这一点。谢谢!
机翻自 https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html