Rust 团队很高兴宣布 Rust 的新版本 1.41.0。Rust 是一种编程语言,它让每个人都能构建可靠高效的软件。
如果您之前通过 rustup 安装了 Rust,获取 Rust 1.41.0 就像这样简单
$ rustup update stable
如果您还没有,您可以从我们网站上的相应页面获取 rustup
,并查看 GitHub 上的1.41.0 的详细发布说明。
1.41.0 稳定版中的新内容
Rust 1.41.0 的亮点包括放宽了对特征实现的限制、对 cargo install
的改进、更友好的 git
Cargo.lock
以及针对 Box<T>
的新的 FFI 相关保证。查看详细的发布说明,了解本文未涵盖的其他更改。
实现特征时的限制放宽
为了防止依赖项添加新的特征 impl
时破坏生态系统,Rust 强制执行孤儿规则。其要点是,只有当特征或正在实现的类型本地于(定义在)当前箱子中而不是外部箱子中时,才允许特征 impl
。这到底意味着什么很复杂,但是,当涉及泛型时。
在 Rust 1.41.0 之前,孤儿规则过于严格,阻碍了组合。例如,假设您的箱子定义了 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
都定义在标准库中,而标准库对于当前箱子来说是外部的。有一些方法可以解决此限制,例如新类型模式,但它们通常很麻烦,甚至在某些情况下是不可能的。
虽然 From
和 Vec
都是外部的,但特征(在本例中为 From
)是通过本地类型参数化的。因此,Rust 1.41.0 允许此 impl
。
cargo install
在过时时更新软件包
使用 cargo install
,您可以在系统中安装二进制箱子。该命令通常被社区用来安装用 Rust 编写的流行 CLI 工具。
从 Rust 1.41.0 开始,如果自您安装以来发布了新版本,cargo install
还会更新箱子的现有安装。在此版本之前,唯一的选项是传递 --force
标志,即使箱子是最新的,也会重新安装它。
Cargo.lock
格式
更不容易发生冲突的 为了确保一致的构建,Cargo 使用一个名为 Cargo.lock
的文件,其中包含依赖项版本和校验和。不幸的是,数据在其中的排列方式会导致在不同分支中更改依赖项时出现不必要的合并冲突。
Rust 1.41.0 引入了该文件的全新格式,明确设计为避免这些冲突。这种新格式将用于所有新的锁定文件,而现有的锁定文件将继续依赖于以前的格式。您可以在添加它的 PR 中了解导致新格式的选择。
Box<T>
时提供更多保证
在 FFI 中使用 从 Rust 1.41.0 开始,我们已经声明 Box<T>
(其中 T: Sized
)现在与 C 语言的指针 (T*
) 类型具有 ABI 兼容性。因此,如果您有一个 extern "C"
Rust 函数,从 C 调用,您的 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。没有你们,我们不可能做到。 感谢!