发布 Rust 1.86.0

2025 年 4 月 3 日 · Rust 发布团队

Rust 团队很高兴宣布 Rust 的新版本,1.86.0。Rust 是一门赋予每个人构建可靠且高效软件能力的编程语言。

如果您通过 rustup 安装了 Rust 的早期版本,您可以通过以下方式获取 1.86.0:

$ rustup update stable

如果您尚未安装,可以从我们网站的相应页面获取 rustup,并查看1.86.0 的详细发行说明

如果您想通过测试未来版本来帮助我们,您可以考虑在本地更新使用 beta 通道(rustup default beta)或 nightly 通道(rustup default nightly)。请报告您可能遇到的任何错误!

1.86.0 稳定版包含的内容

Trait 上溯转换

此版本包含一项期待已久的功能—— trait 对象上溯转换的能力。如果一个 trait 有一个父 trait,您可以将对该 trait 对象的引用强制转换为对其父 trait 的 trait 对象的引用

trait Trait: Supertrait {}
trait Supertrait {}

fn upcast(x: &dyn Trait) -> &dyn Supertrait {
    x
}

这同样适用于任何其他类型的(智能)指针,例如 Arc<dyn Trait> -> Arc<dyn Supertrait>*const dyn Trait -> *const dyn Supertrait

以前,这需要一种变通方法,即在 Trait 本身中添加一个 upcast 方法,例如 fn as_supertrait(&self) -> &dyn Supertrait,并且这仅适用于一种引用/指针类型。现在不再需要这种变通方法了。

请注意,这意味着指向 trait 对象的裸指针带有一个非平凡的不变量:将指向带有无效 vtable 的 trait 对象的裸指针“泄露”到安全代码中可能导致未定义行为。目前尚未决定在良好控制的情况下临时创建此类裸指针是否会立即导致未定义行为,因此在任何情况下都应避免创建此类指针(Miri 会强制执行此点)。

Trait 上溯转换与 Any trait 结合使用时可能特别有用,因为它允许将您的 trait 对象上溯转换为 dyn Any 以调用 Any 的下溯转换方法,而无需添加任何 trait 方法或使用外部 crate。

use std::any::Any;

trait MyAny: Any {}

impl dyn MyAny {
    fn downcast_ref<T>(&self) -> Option<&T> {
        (self as &dyn Any).downcast_ref()
    }
}

您可以在Rust 参考手册中了解更多关于 trait 上溯转换的信息

HashMap 和切片现在支持可变地索引多个元素

借用检查器阻止了对 get_mut 方法的重复调用所获得的引用的同时使用。为了安全地支持这种模式,标准库现在在切片和 HashMap 上提供了一个 get_disjoint_mut 辅助方法以同时获取多个元素的可变引用。请参阅slice::get_disjoint_mut 的 API 文档中的以下示例

let v = &mut [1, 2, 3];
if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) {
    *a = 413;
    *b = 612;
}
assert_eq!(v, &[413, 2, 612]);

if let Ok([a, b]) = v.get_disjoint_mut([0..1, 1..3]) {
    a[0] = 8;
    b[0] = 88;
    b[1] = 888;
}
assert_eq!(v, &[8, 88, 888]);

if let Ok([a, b]) = v.get_disjoint_mut([1..=2, 0..=0]) {
    a[0] = 11;
    a[1] = 111;
    b[0] = 1;
}
assert_eq!(v, &[1, 11, 111]);

允许用 #[target_feature] 属性标记安全函数。

以前只有 unsafe 函数可以用 #[target_feature] 属性标记,因为在未启用目标特性时调用此类函数是不健全的(unsound)。此版本稳定了 target_feature_11 特性,允许用 #[target_feature] 属性标记安全函数。

标记有目标特性属性的安全函数只能从同样标记有目标特性属性的其他函数中安全地调用。但是,它们不能传递给接受受 Fn* traits 约束的泛型函数,并且仅支持在标记有 target_feature 属性的函数内部强制转换为函数指针。

在未标记有目标特性属性的函数内部,它们可以在 unsafe 块内部被调用,但调用者有责任确保目标特性是可用的。

#[target_feature(enable = "avx2")]
fn requires_avx2() {
    // ... snip
}

#[target_feature(enable = "avx2")]
fn safe_callsite() {
    // Calling `requires_avx2` here is safe as `safe_callsite`
    // requires the `avx2` feature itself.
    requires_avx2();
}

fn unsafe_callsite() {
    // Calling `requires_avx2` here is unsafe, as we must
    // ensure that the `avx2` feature is available first.
    if is_x86_feature_detected!("avx2") {
        unsafe { requires_avx2() };
    }
}

您可以查看target_features_11 RFC 以获取更多信息。

出于健全性(soundness)要求时,对非空指针进行调试断言

现在,编译器将在非零大小的读写以及将指针重新借用为引用时插入指针非空的调试断言。例如,当启用调试断言时,以下代码现在会产生一个不会展开(non-unwinding)的 panic:

let _x = *std::ptr::null::<u8>();
let _x = &*std::ptr::null::<u8>();

像这样的简单例子自 Rust 1.53.0 起就会产生警告,新的运行时检查将检测到这些场景,无论其复杂性如何。

这些断言仅在启用调试断言时发生,这意味着它们不能作为健全性(soundness)的依赖。这也意味着已禁用调试断言编译的依赖项(例如标准库)即使被启用了调试断言的代码调用,也不会触发这些断言。

默认将 missing_abi lint 升级为警告

在 extern 块和函数中省略 ABI(例如 extern {}extern fn)现在将导致一个警告(通过 missing_abi lint)。在 extern 关键字后省略 ABI 始终隐式地导致使用 "C" ABI。现在建议显式指定 "C" ABI(例如 extern "C" {}extern "C" fn)。

您可以查看显式 Extern ABI RFC 以获取更多信息。

1.87.0 版本目标弃用警告

二级目标 i586-pc-windows-msvc 将在下一个 Rust 版本 1.87.0 中移除。它与更受欢迎的 i686-pc-windows-msvc 的区别在于它不需要 SSE2 指令支持,但所有 windows 目标(win7 目标除外)的最低要求操作系统 Windows 10 本身就需要 SSE2 指令。

所有当前针对 i586-pc-windows-msvc 的用户都应在 1.87.0 版本发布前迁移到 i686-pc-windows-msvc

您可以查看重大变更提案以获取更多信息。

稳定化的 API

这些 API 现在在 const 上下文中稳定

其他变更

查看RustCargoClippy 中的所有变更。

1.86.0 贡献者

许多人共同促成了 Rust 1.86.0 的发布。没有你们的支持,这一切都不可能实现。感谢大家!