发布 Rust 1.41.0

2020 年 1 月 30 日 · Rust 发布团队

Rust 团队很高兴发布新版本 Rust 1.41.0。Rust 是一门编程语言,它使每个人都能够构建可靠且高效的软件。

如果你已经通过 rustup 安装了之前版本的 Rust,获取 Rust 1.41.0 非常简单,只需执行以下命令:

$ rustup update stable

如果你还没有安装,可以从我们网站上的相应页面获取 rustup,并在 GitHub 上查看 1.41.0 的详细发布说明

1.41.0 stable 版本有什么新内容

Rust 1.41.0 的亮点包括放宽 trait 实现的限制、对 cargo install 的改进、更友好的 git Cargo.lock 文件以及对 Box<T> 新的 FFI 相关保证。请参阅详细发布说明,了解本文未涵盖的其他更改。

放宽 trait 实现时的限制

为了防止当某个依赖项添加新的 trait impl 时导致生态系统中断,Rust 强制执行孤儿规则(orphan rule)。其要点是,只有当 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 被孤儿规则禁止,因为 FromVec 都定义在标准库中,对于当前 crate 来说是外部的。有一些方法可以绕过这个限制,例如新类型模式(newtype pattern),但它们通常很麻烦,在某些情况下甚至不可能实现。

虽然 FromVec 仍然是外部的,但该 trait(在本例中为 From)被一个本地类型参数化了。因此,Rust 1.41.0 允许了这种 impl

有关更多详细信息,请阅读稳定化报告提议此更改的 RFC

cargo install 在包过时时进行更新

使用 cargo install,你可以在你的系统中安装二进制 crate。社区经常使用此命令来安装用 Rust 编写的流行 CLI 工具。

从 Rust 1.41.0 开始,如果自你安装某个 crate 以来发布了新版本,cargo install 也会更新现有的安装。在此版本之前,唯一的选项是传递 --force 标志,即使二进制 crate 是最新的,它也会重新安装。

冲突更少的 Cargo.lock 格式

为了确保构建的一致性,Cargo 使用一个名为 Cargo.lock 的文件,其中包含依赖项的版本和校验和。不幸的是,文件中数据的排列方式在不同分支更改依赖项时导致了不必要的合并冲突。

Rust 1.41.0 引入了文件的新格式,明确旨在避免这些冲突。新格式将用于所有新的 lockfile,而现有的 lockfile 仍将依赖于旧格式。你可以在添加此格式的 PR 中了解导致新格式的选择。

在 FFI 中使用 Box<T> 时提供更多保证

从 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 中,我们对标准库进行了以下添加:

即将减少对 32 位 Apple 目标平台的支持

Rust 1.41.0 是当前级别编译器支持 32 位 Apple 目标平台(包括 i686-apple-darwin 目标平台)的最后一个版本。从 Rust 1.42.0 开始,这些目标平台将被降级到最低支持层级。

你可以在这篇博客文章中了解更多关于此更改的信息。

其他更改

Rust 1.41.0 版本还有其他更改:请查看 RustCargoClippy 的更改内容。我们还开始引入 MIR 优化,这应该能改善编译时间:你可以在《Inside Rust》博客文章中了解更多信息。

1.41.0 的贡献者

许多人共同努力创建了 Rust 1.41.0。没有你们所有人的贡献,我们不可能做到。感谢!