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
在循环中执行 Vec::push
4 次
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 后端,从而提高了运行时性能和内存使用率。
1.66.0 的贡献者
许多人共同创建了 Rust 1.66.0。没有你们,我们不可能做到。 感谢!