Rust 团队很高兴地宣布 Rust 新版本 1.41.0 发布。Rust 是一种旨在让每个人都能构建可靠且高效软件的编程语言。
如果您之前通过 rustup 安装了 Rust,那么获取 Rust 1.41.0 版本非常简单,只需运行:
$ rustup update stable
如果您还没有安装 Rust,您可以从我们的网站上的相应页面获取 rustup
,并查看 GitHub 上 1.41.0 版本的详细发布说明。
1.41.0 稳定版的新特性
Rust 1.41.0 的亮点包括放宽了 trait 实现的限制,改进了 cargo install
,更利于 git
的 Cargo.lock
,以及为 Box<T>
提供了新的 FFI 相关保证。请参阅详细发布说明,了解本文未涵盖的其他更改。
放宽 trait 实现的限制
为了防止在依赖项添加新的 trait impl
时破坏生态系统,Rust 强制执行了孤儿规则。其要点是,只有当 trait 或要实现的类型对于当前 crate 来说是本地的(在当前 crate 中定义),而不是外部的 crate 时,才允许 trait impl
。其确切含义在涉及泛型时会变得复杂。
在 Rust 1.41.0 之前,孤儿规则不必要地严格,妨碍了组合。例如,假设您的 crate 定义了 BetterVec<T>
结构体,并且您希望有一种方法将您的结构体转换为标准库的 Vec<T>
。您会编写的代码是:
impl<T> From<BetterVec<T>> for Vec<T> {
// ...
}
...这是以下模式的一个实例:
impl<T> ForeignTrait<LocalType> for ForeignType<T> {
// ...
}
在 Rust 1.40.0 中,这个 impl
被孤儿规则禁止,因为 From
和 Vec
都在标准库中定义,这对于当前 crate 来说是外部的。有一些方法可以绕过这个限制,例如newtype 模式,但在某些情况下,这些方法通常很麻烦,甚至不可能实现。
虽然 From
和 Vec
仍然是外部的,但 trait(在本例中是 From
)是由本地类型参数化的。因此,Rust 1.41.0 允许了这个 impl
。
cargo install
在软件包过时时更新
使用 cargo install
,您可以在系统中安装二进制 crate。该命令通常被社区用于安装用 Rust 编写的流行 CLI 工具。
从 Rust 1.41.0 开始,如果自您安装以来有新版本发布,cargo install
也会更新 crate 的现有安装。在此版本之前,唯一的选择是传递 --force
标志,即使二进制 crate 是最新的,也会重新安装它。
Cargo.lock
格式
减少冲突的 为了确保构建的一致性,Cargo 使用名为 Cargo.lock
的文件,其中包含依赖项版本和校验和。不幸的是,数据在其中排列的方式导致在不同分支中更改依赖项时出现不必要的合并冲突。
Rust 1.41.0 为该文件引入了一种新格式,专门设计用于避免这些冲突。这种新格式将用于所有新的 lockfile,而现有的 lockfile 仍将依赖于以前的格式。您可以在添加它的 PR 中了解导致新格式的选择。
Box<T>
进行 FFI 时提供更多保证
在使用 从 Rust 1.41.0 开始,我们声明 Box<T>
(其中 T: Sized
)现在与 C 语言的指针(T*
)类型 ABI 兼容。因此,如果您有一个从 C 调用的 extern "C"
Rust 函数,您的 Rust 函数现在可以使用 Box<T>
(对于某些特定的 T
),同时在 C 中为相应的函数使用 T*
。例如,在 C 端,您可能有:
// C header
// Returns ownership to the caller.
struct Foo* foo_new(void);
// Takes ownership from the caller; no-op when invoked with NULL.
void foo_delete(struct Foo*);
...而在 Rust 端,您将有:
#[repr(C)]
pub struct Foo;
#[no_mangle]
pub extern "C" fn foo_new() -> Box<Foo> {
Box::new(Foo)
}
// The possibility of NULL is represented with the `Option<_>`.
#[no_mangle]
pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
但请注意,虽然 Box<T>
和 T*
具有相同的表示形式和 ABI,但 Box<T>
仍然必须是非空的、对齐的,并且准备好由全局分配器释放。为了确保这一点,最好只使用来自全局分配器的 Box
。
重要提示: 至少目前,您应该避免对在 C 中定义但在 Rust 中调用的函数使用 Box<T>
类型。在这些情况下,您应该直接尽可能地镜像 C 类型。在 C 定义仅使用 T*
的情况下使用 Box<T>
等类型可能会导致未定义的行为。
要了解更多信息,请查阅 Box<T>
的文档。
库变更
在 Rust 1.41.0 中,我们向标准库添加了以下内容:
-
Result::map_or
和Result::map_or_else
方法已稳定化。与
Option::map_or
和Option::map_or_else
类似,这些方法是.map(|val| process(val)).unwrap_or(default)
模式的简写形式。 -
NonZero*
数值类型现在实现了From<NonZero*>
,如果它是较小的整数宽度。 例如,NonZeroU16
现在实现了From<NonZeroU8>
。 -
Weak
指针上的weak_count
和strong_count
方法已稳定化。std::rc::Weak::weak_count
std::rc::Weak::strong_count
std::sync::Weak::weak_count
std::sync::Weak::strong_count
这些方法分别返回指向分配的弱指针(
rc::Weak<T>
和sync::Weak<T>
)或强指针(Rc<T>
和Arc<T>
)的数量。
即将减少对 32 位 Apple 目标的支持
Rust 1.41.0 是最后一个对 32 位 Apple 目标(包括 i686-apple-darwin
目标)提供当前级别编译器支持的版本。从 Rust 1.42.0 开始,这些目标将被降级到最低支持级别。
其他变更
Rust 1.41.0 版本中还有其他更改:请查看 Rust、Cargo 和 Clippy 中的更改内容。我们还开始实施 MIR 优化,这应该可以提高编译时间:您可以在“Inside Rust”博客文章中了解有关它们的更多信息。
1.41.0 版本的贡献者
许多人共同努力创建了 Rust 1.41.0。没有你们大家,我们不可能做到。谢谢!