Rust 团队发布了 Rust 的新版本 1.59.0。Rust 是一种旨在帮助所有人构建可靠且高效软件的编程语言。
今天的发布正值全世界的目光都聚焦于普京军队突然入侵乌克兰之际。在深入了解 Rust 新版本的细节之前,我们想声明,我们与乌克兰人民站在一起,并对所有受这场冲突影响的人们表示支持。
如果您之前通过 rustup 安装了 Rust,您可以使用以下命令获取 1.59.0 版本:
$ rustup update stable
如果您还没有安装,您可以从我们网站上的相应页面获取 rustup
,并查看 GitHub 上 1.59.0 版本的详细发布说明。
1.59.0 稳定版的新特性
内联汇编
Rust 语言现在支持内联汇编。这为许多需要对其执行进行极低级别控制或访问专用机器指令的应用程序提供了可能。
例如,在为 x86-64 目标编译时,您现在可以编写:
use std::arch::asm;
// Multiply x by 6 using shifts and adds
let mut x: u64 = 4;
unsafe {
asm!(
"mov {tmp}, {x}",
"shl {tmp}, 1",
"shl {x}, 2",
"add {x}, {tmp}",
x = inout(reg) x,
tmp = out(reg) _,
);
}
assert_eq!(x, 4 * 6);
用于在 asm!
和 global_asm!
宏中命名寄存器的格式字符串语法与 Rust 格式字符串 中使用的语法相同,因此 Rust 程序员应该会感到非常熟悉。
内联汇编中可用的汇编语言和指令因目标架构而异。今天,稳定的 Rust 编译器在以下架构上支持内联汇编:
- x86 和 x86-64
- ARM
- AArch64
- RISC-V
您可以在 Rust By Example 中查看更多内联汇编的示例,并在 参考文档 中找到更详细的文档。
解构赋值
您现在可以使用元组、切片和结构体模式作为赋值的左侧。
let (a, b, c, d, e);
(a, b) = (1, 2);
[c, .., d, _] = [1, 2, 3, 4, 5];
Struct { e, .. } = Struct { e: 5, f: 3 };
assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]);
这使得赋值与长期以来支持相同功能的 let
绑定更加一致。请注意,不允许使用 +=
等运算符进行解构赋值。
常量泛型默认值和交错
泛型类型现在可以为其常量泛型指定默认值。例如,您现在可以编写以下代码:
struct ArrayStorage<T, const N: usize = 2> {
arr: [T; N],
}
impl<T> ArrayStorage<T> {
fn new(a: T, b: T) -> ArrayStorage<T> {
ArrayStorage {
arr: [a, b],
}
}
}
以前,类型参数必须在所有常量参数之前。该限制已被放宽,您现在可以交错它们。
fn cartesian_product<
T, const N: usize,
U, const M: usize,
V, F
>(a: [T; N], b: [U; M], f: F) -> [[V; N]; M]
where
F: FnMut(&T, &U) -> V
{
// ...
}
未来不兼容警告
有时 Rust 编译器中的错误会导致它接受本不应接受的代码。这方面的一个例子是安全代码中允许借用 packed 结构体字段。
虽然这种情况很少发生,但当您的项目使用的 crate 中包含将来不再允许的代码时,可能会非常具有破坏性。事实上,您可能直到项目莫名其妙地停止构建才会注意到!
Cargo 现在会在依赖项将被未来版本的 Rust 拒绝时显示警告。运行 cargo build
或 cargo check
后,您可能会看到:
warning: the following packages contain code that will be rejected by a future version of Rust: old_dep v0.1.0
note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1`
您可以运行警告中提到的 cargo report
命令来查看将被拒绝的完整代码报告。这使您有时间在依赖项破坏您的构建之前升级它。
创建剥离二进制文件
从您分发的二进制文件中剥离不必要的信息(如 debuginfo)通常很有用,这可以使它们更小。
虽然在创建二进制文件后手动执行此操作一直是可以的,但 cargo 和 rustc 现在支持在链接二进制文件时进行剥离。要启用此功能,请将以下内容添加到您的 Cargo.toml
中:
[profile.release]
strip = "debuginfo"
这会导致 debuginfo 从发布二进制文件中剥离。您还可以提供 "symbols"
或仅提供 true
以在支持的情况下剥离所有符号信息。
标准库通常附带调试符号和行级 debuginfo,因此默认情况下,在不启用调试符号的情况下构建的 Rust 二进制文件仍然包含来自标准库的调试信息。使用 strip
选项允许您删除此额外信息,从而生成更小的 Rust 二进制文件。
有关更多详细信息,请参阅 Cargo 的文档。
默认禁用增量编译
1.59.0 版本默认禁用增量编译(除非通过环境变量显式请求:RUSTC_FORCE_INCREMENTAL=1
)。这缓解了一个已知错误 #94124 的影响,该错误可能导致在启用增量编译的情况下编译期间出现反序列化错误(和 panic)。
#94124 的具体修复已落地,目前在 1.60 beta 版本中,该版本将在六周后发布。我们目前没有意识到其他问题会促使我们决定在 1.60 稳定版中禁用增量编译,如果没有任何问题出现,1.60 稳定版很可能会再次重新启用增量编译。增量编译在 beta 和 nightly 频道中仍然默认启用。
与往常一样,我们鼓励用户在 nightly 和 beta 频道上进行测试并报告您发现的问题:特别是对于增量错误,这是确保 Rust 团队可以判断是否存在破坏以及影响的用户数量的最佳方法。
稳定的 API
以下方法和 trait 实现现在已稳定:
std::thread::available_parallelism
Result::copied
Result::cloned
arch::asm!
arch::global_asm!
ops::ControlFlow::is_break
ops::ControlFlow::is_continue
TryFrom<char> for u8
char::TryFromCharError
实现Clone
、Debug
、Display
、PartialEq
、Copy
、Eq
、Error
iter::zip
NonZeroU8::is_power_of_two
NonZeroU16::is_power_of_two
NonZeroU32::is_power_of_two
NonZeroU64::is_power_of_two
NonZeroU128::is_power_of_two
DoubleEndedIterator for ToLowercase
DoubleEndedIterator for ToUppercase
TryFrom<&mut [T]> for [T; N]
UnwindSafe for Once
RefUnwindSafe for Once
- aarch64 的 armv8 neon intrinsics
以下先前稳定的函数现在是 const
:
mem::MaybeUninit::as_ptr
mem::MaybeUninit::assume_init
mem::MaybeUninit::assume_init_ref
ffi::CStr::from_bytes_with_nul_unchecked
其他更改
Rust 1.59.0 版本中还有其他更改。查看 Rust、Cargo 和 Clippy 中的更改内容。
1.59.0 版本的贡献者
许多人齐心协力创建了 Rust 1.59.0。没有你们所有人,我们不可能做到。谢谢!