Rust 团队很高兴地宣布 Rust 的新版本 1.66.0。Rust 是一种编程语言,它使每个人都能够构建可靠且高效的软件。
如果您通过 rustup 安装了以前版本的 Rust,可以使用以下命令获取 1.66.0:
$ rustup update stable
如果您还没有安装,可以从我们网站上的相应页面获取 rustup
,并查看 GitHub 上 1.66.0 的详细发行说明。
如果您想通过测试未来的版本来帮助我们,您可以考虑在本地更新以使用 beta 频道 (rustup default beta
) 或 nightly 频道 (rustup default nightly
)。请报告您可能遇到的任何错误!
1.66.0 稳定版中的新功能
带有字段的枚举上的显式判别式
具有整数表示形式的枚举现在可以使用显式判别式,即使它们有字段。
#[repr(u8)]
enum Foo {
A(u8),
B(i8),
C(bool) = 42,
}
以前,您可以在带有表示形式的枚举上使用显式判别式,但前提是它们的任何变体都没有字段。当在跨语言边界传递值时,显式判别式很有用,在这种情况下,枚举的表示形式需要在两种语言中匹配。例如,
#[repr(u8)]
enum Bar {
A,
B,
C = 42,
D,
}
这里保证 Bar
枚举与 u8
具有相同的布局。此外,保证 Bar::C
变体的判别式为 42。没有显式指定值的变体将具有根据它们在源代码中的顺序自动分配的判别式,因此 Bar::A
的判别式为 0,Bar::B
的判别式为 1,Bar::D
的判别式为 43。如果没有此功能,设置 Bar::C
的显式值的唯一方法是在它之前添加 41 个不必要的变体!
注意:虽然对于无字段枚举,可以通过 as
转换来检查判别式(例如 Bar::C as u8
),但 Rust 没有提供语言级别的方式来访问带有字段的枚举的原始判别式。相反,目前必须使用不安全的代码来检查带有字段的枚举的判别式。由于此功能旨在用于跨语言 FFI(其中已经需要不安全的代码),因此这应该不会造成太大的额外负担。与此同时,如果所有您需要的只是判别式的不透明句柄,请参阅 std::mem::discriminant
函数。
core::hint::black_box
在基准测试或检查编译器生成的机器代码时,通常需要阻止某些位置发生优化。在以下示例中,函数 push_cap
在循环中执行 4 次 Vec::push
fn push_cap(v: &mut Vec<i32>) {
for i in 0..4 {
v.push(i);
}
}
pub fn bench_push() -> Duration {
let mut v = Vec::with_capacity(4);
let now = Instant::now();
push_cap(&mut v);
now.elapsed()
}
如果您检查 x86_64 上编译器优化的输出,您会注意到它看起来相当短
example::bench_push:
sub rsp, 24
call qword ptr [rip + std::time::Instant::now@GOTPCREL]
lea rdi, [rsp + 8]
mov qword ptr [rsp + 8], rax
mov dword ptr [rsp + 16], edx
call qword ptr [rip + std::time::Instant::elapsed@GOTPCREL]
add rsp, 24
ret
实际上,我们想要基准测试的整个函数 push_cap
已被优化掉了!
我们可以使用新稳定的 black_box
函数来解决这个问题。在功能上,black_box
不是很吸引人:它接受您传递给它的值并将其直接返回。但是,在内部,编译器将 black_box
视为一个可以对其输入执行任何操作并返回任何值的函数(正如其名称所暗示的那样)。
这对于禁用像上面我们看到的优化非常有用。例如,我们可以提示编译器,在 for 循环的每次迭代之后,该向量实际上会被用于某些事情。
use std::hint::black_box;
fn push_cap(v: &mut Vec<i32>) {
for i in 0..4 {
v.push(i);
black_box(v.as_ptr());
}
}
现在我们可以在我们的 优化的汇编输出中找到展开的 for 循环
mov dword ptr [rbx], 0
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 4], 1
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 8], 2
mov qword ptr [rsp + 8], rbx
mov dword ptr [rbx + 12], 3
mov qword ptr [rsp + 8], rbx
您还可以看到在此汇编输出中调用 black_box
的副作用。指令 mov qword ptr [rsp + 8], rbx
在每次迭代后都无用地重复。此指令将地址 v.as_ptr()
写为函数的第一个参数,该函数实际上从未被调用。
请注意,生成的代码根本不关心 push
调用引入的分配的可能性。这是因为编译器仍然使用我们在 bench_push
函数中调用 Vec::with_capacity(4)
的事实。您可以尝试使用 black_box
的放置位置,或尝试在多个位置使用它,以查看其对编译器优化的影响。
cargo remove
在 Rust 1.62.0 中,我们引入了 cargo add
,一个用于向您的项目添加依赖项的命令行实用程序。现在您可以使用 cargo remove
删除依赖项。
稳定的 API
proc_macro::Span::source_text
u*::{checked_add_signed, overflowing_add_signed, saturating_add_signed, wrapping_add_signed}
i*::{checked_add_unsigned, overflowing_add_unsigned, saturating_add_unsigned, wrapping_add_unsigned}
i*::{checked_sub_unsigned, overflowing_sub_unsigned, saturating_sub_unsigned, wrapping_sub_unsigned}
BTreeSet::{first, last, pop_first, pop_last}
BTreeMap::{first_key_value, last_key_value, first_entry, last_entry, pop_first, pop_last}
- 为 WASI 上的 stdio 锁类型添加
AsFd
实现。 impl TryFrom<Vec<T>> for Box<[T; N]>
core::hint::black_box
Duration::try_from_secs_{f32,f64}
Option::unzip
std::os::fd
其他更改
Rust 1.66 版本还有其他更改,包括:
- 您现在可以在模式中使用
..=X
范围。 - Linux 构建现在分别使用 LTO 和 BOLT 优化 rustc 前端和 LLVM 后端,从而提高运行时性能和内存使用率。
查看 Rust、Cargo 和 Clippy 中更改的所有内容。
1.66.0 的贡献者
许多人齐心协力创建了 Rust 1.66.0。没有大家,我们就无法做到这一点。谢谢!