宣布 Rust 1.64.0

2022 年 9 月 22 日 · Rust 发布团队

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

如果您之前通过 rustup 安装了 Rust,您可以使用以下命令获取 1.64.0

$ rustup update stable

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

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

1.64.0 稳定版中的内容

使用 IntoFuture 增强 .await

Rust 1.64 稳定了IntoFuture 特性。IntoFuture 是一个类似于IntoIterator 的特性,但它不是支持 for ... in ... 循环,而是改变了 .await 的工作方式。使用 IntoFuture.await 关键字可以等待的不仅仅是 futures;它可以等待任何可以通过 IntoFuture 转换为 Future 的东西 - 这可以帮助使您的 API 更易于使用!

例如,一个构建器通过网络构建对某个存储提供商的请求

pub struct Error { ... }
pub struct StorageResponse { ... }:
pub struct StorageRequest(bool);

impl StorageRequest {
    /// Create a new instance of `StorageRequest`.
    pub fn new() -> Self { ... }
    /// Decide whether debug mode should be enabled.
    pub fn set_debug(self, b: bool) -> Self { ... }
    /// Send the request and receive a response.
    pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}

典型的用法可能如下所示

let response = StorageRequest::new()  // 1. create a new instance
    .set_debug(true)                  // 2. set some option
    .send()                           // 3. construct the future
    .await?;                          // 4. run the future + propagate errors

这并不差,但我们可以做得更好。使用 IntoFuture,我们可以将“构建 future”(第 3 行)和“运行 future”(第 4 行)合并到一个步骤中

let response = StorageRequest::new()  // 1. create a new instance
    .set_debug(true)                  // 2. set some option
    .await?;                          // 3. construct + run the future + propagate errors

我们可以通过为 StorageRequest 实现 IntoFuture 来做到这一点。IntoFuture 要求我们有一个可以返回的命名 future,我们可以通过创建一个“boxed future”并为其定义一个类型别名来做到这一点

// First we must import some new types into the scope.
use std::pin::Pin;
use std::future::{Future, IntoFuture};

pub struct Error { ... }
pub struct StorageResponse { ... }
pub struct StorageRequest(bool);

impl StorageRequest {
    /// Create a new instance of `StorageRequest`.
    pub fn new() -> Self { ... }
    /// Decide whether debug mode should be enabled.
    pub fn set_debug(self, b: bool) -> Self { ... }
    /// Send the request and receive a response.
    pub async fn send(self) -> Result<StorageResponse, Error> { ... }
}

// The new implementations:
// 1. create a new named future type
// 2. implement `IntoFuture` for `StorageRequest`
pub type StorageRequestFuture = Pin<Box<dyn Future<Output = Result<StorageResponse, Error>> + Send + 'static>>
impl IntoFuture for StorageRequest {
    type IntoFuture = StorageRequestFuture;
    type Output = <StorageRequestFuture as Future>::Output;
    fn into_future(self) -> Self::IntoFuture {
        Box::pin(self.send())
    }
}

这需要更多代码来实现,但为用户提供了更简单的 API。

将来,Rust Async WG 希望通过支持impl Traittype 别名中(类型别名实现特性或 TAIT) 来简化创建新的命名 futures。这应该通过简化类型别名的签名来使实现 IntoFuture 更容易,并通过从类型别名中删除 Box 来提高性能。

core 和 alloc 中的 C 兼容 FFI 类型

在调用或被 C ABI 调用时,Rust 代码可以使用类型别名(如 c_uintc_ulong)来匹配任何目标上来自 C 的相应类型,而无需目标特定的代码或条件。

以前,这些类型别名只在 std 中可用,因此为嵌入式目标和其他只能使用 corealloc 的场景编写的代码无法使用这些类型。

Rust 1.64 现在在core::ffi 中提供了所有 c_* 类型别名,以及core::ffi::CStr 用于处理 C 字符串。Rust 1.64 还提供了alloc::ffi::CString 用于处理使用 alloc 而不是完整的 std 库的拥有 C 字符串。

rust-analyzer 现在可以通过 rustup 获取

rust-analyzer 现在已包含在 Rust 附带的工具集中。这使得下载和访问 rust-analyzer 更容易,并且使其在更多平台上可用。它作为rustup 组件 可用,可以使用以下命令安装

rustup component add rust-analyzer

目前,要运行 rustup 安装的版本,您需要以这种方式调用它

rustup run stable rust-analyzer

rustup 的下一个版本将提供一个内置代理,以便运行可执行文件 rust-analyzer 将启动相应的版本。

大多数用户应该继续使用 rust-analyzer 团队提供的版本(在rust-analyzer 发布页面 上可用),这些版本发布频率更高。使用官方 VSCode 扩展 的用户不受影响,因为它会在后台自动下载和更新版本。

Cargo 改进:工作区继承和多目标构建

在使用一个 Cargo 工作区中的相关库或二进制箱的集合时,您现在可以避免在箱之间重复公共字段值,例如公共版本号、存储库 URL 或 rust-version。这也有助于在更新这些值时保持箱之间同步。有关更多详细信息,请参阅workspace.packageworkspace.dependencies“从工作区继承依赖项”

在为多个目标构建时,您现在可以将多个 --target 选项传递给 cargo build,以一次构建所有这些目标。您还可以将build.target 设置为 .cargo/config.toml 中的多个目标数组,以默认情况下为多个目标构建。

稳定的 API

以下方法和特性实现现在已稳定

这些类型以前在 std::ffi 中是稳定的,但现在也适用于 corealloc

这些类型以前在 std::os::raw 中是稳定的,但现在也适用于 core::ffistd::ffi

我们稳定了一些用于 Poll 的帮助程序,Poll 是 futures 底层的低级实现

将来,我们希望提供更简单的 API,这些 API 需要更少地使用 PollPin 等低级细节,但在此期间,这些帮助程序使编写此类代码更容易。

这些 API 现在可以在 const 上下文中使用

兼容性说明

  • 之前宣布linux 目标现在至少需要 Linux 内核 3.2(除了已经需要更新内核的目标),而 linux-gnu 目标现在需要 glibc 2.17(除了已经需要更新 glibc 的目标)。

  • Rust 1.64.0 更改了 Ipv4AddrIpv6AddrSocketAddrV4SocketAddrV6 的内存布局,使其更紧凑且内存效率更高。这种内部表示从未公开,但一些箱仍然通过使用 std::mem::transmute 依赖于它,导致无效的内存访问。标准库的此类内部实现细节绝不被视为稳定的接口。为了最大程度地减少损害,我们与所有仍在维护的执行此操作的箱的作者合作,发布了修复版本,这些版本已经发布了一年多。大多数受影响的用户应该能够通过 cargo update 来缓解。

  • 作为RLS 弃用 的一部分,这也是包含 RLS 副本的最后一个版本。从 Rust 1.65.0 开始,RLS 将被一个显示弃用警告的小型 LSP 服务器取代。

其他更改

Rust 1.64 版本中还有其他更改,包括

  • Rust 编译器的 Windows 版本现在使用配置文件引导优化,为在 Windows 上编译 Rust 代码提供了 10-20% 的性能提升。

  • 如果你定义了一个包含从未使用过的字段的结构体,rustc 会警告你未使用的字段。现在,在 Rust 1.64 中,你可以启用 unused_tuple_struct_fields lint 来获得关于元组结构体中未使用的字段的相同警告。在未来的版本中,我们计划默认情况下使此 lint 发出警告。类型为 unit (()) 的字段不会产生此警告,以便更容易地迁移现有代码,而无需更改元组索引。

查看 RustCargoClippy 中的所有更改。

1.64.0 的贡献者

许多人共同创建了 Rust 1.64.0。没有你们,我们无法做到。 感谢!