Rust 新版解读 | 1.64 | 重点: IntoFuture
, Cargo 优化
Rust 1.64 官方 release doc: Announcing Rust 1.64.0 | Rust Blog
通过 rustup 安装的同学可以使用以下命令升级到 1.64 版本:
$ rustup update stable
使用 IntoFuture
增强 .await
1.64 稳定了 IntoFuture
trait,不同于用在 for ... in ...
的 IntoIterator
trait,IntoFuture
增强了 .awiat
关键字。现在 .await
可以 await 除了 futures 外,还可以 await 任何实现了 IntoFuture
trait 并经此转换成 Future
的对象。这可以让你的 api 对用户更加优化。
举一个用在网络存储供应端的例子:
#![allow(unused)] fn main() { pub struct Error { ... } pub struct StorageResponse { ... }: pub struct StorageRequest(bool); impl StorageRequest { /// 实例化一个 `StorageRequest` pub fn new() -> Self { ... } /// 是否开启 debug 模式 pub fn set_debug(self, b: bool) -> Self { ... } /// 发送请求并接受回复 pub async fn send(self) -> Result<StorageResponse, Error> { ... } } }
通常地使用方法可能类似如下代码:
#![allow(unused)] fn main() { let response = StorageRequest::new() // 1. 实例化 .set_debug(true) // 2. 设置一些选项 .send() // 3. 构造 future .await?; // 4. 执行 future ,传递 error }
这个代码已经不错了,不过 1.64 后可以做的更好。使用 IntoFuture
,把第三步的 “构造 future ” 和 第四步的 “执行 future ” 合并到一个步骤里:
let response = StorageRequest::new() // 1. 实例化
.set_debug(true) // 2. 设置一些选项
.await?; // 3. 构造并执行 future ,传递 error
想要实现上面的效果,我们需要给 StorageRequest
实现 IntoFuture
trait。IntoFuture
需要确定好要返回的 future,可以用下面的代码来实现:
#![allow(unused)] fn main() { // 首先需要引入一些必须的类型 use std::pin::Pin; use std::future::{Future, IntoFuture}; pub struct Error { ... } pub struct StorageResponse { ... } pub struct StorageRequest(bool); impl StorageRequest { /// 实例化一个 `StorageRequest` pub fn new() -> Self { ... } /// 是否开启 debug 模式 pub fn set_debug(self, b: bool) -> Self { ... } /// 发送请求并接受回复 pub async fn send(self) -> Result<StorageResponse, Error> { ... } } // 新的实现内容 // 1. 定义好返回的 future 类型 pub type StorageRequestFuture = Pin<Box<dyn Future<Output = Result<StorageResponse, Error>> + Send + 'static>> // 2. 给 `StorageRequest` 实现 `IntoFuture` 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 异步团队 希望能够通过给类型别名提供 impl Trait
Type Alias Impl Trait,来简化定义 futures 实现 IntoFuture
的代码;再想办法移除 Box
来提升性能。
core
和 alloc
中和 C 语言兼容的 FFI 类型
当调用 C-ABI 或者调用 C-ABI 的时候,Rust 代码通常会使用诸如 c_uint
或者 c_ulong
的类型别名来匹配目标语言里的对应类型。
在次之前,这些类型别名仅在 std
里可用,而在嵌入式或者其它仅能使用 core
或者 alloc
的场景下无法使用。
1.64 里在 core::ffi
里提供了所有 c_*
的类型别名,还有 core::ffi::CStr
对应 C 的字符串,还有仅用 alloc
库情况下可以用 alloc::ffi::CString
来对应 C 的字符串。
可以通过 rustup 来使用 rust-analyzer
rust-analyzer 现在被加进 Rust 工具集里了。这让在各平台上下载使用 rust-analyzer 更加方便。通过 rustup component 来安装:
rustup component add rust-analyzer
目前,使用 rustup 安装的版本,需要这样启用:
rustup run stable rust-analyzer
下一次 rustup 的发布本把会提供一个内置的代理,来运行对应版本的 rust-analyzer 。
Cargo 优化,workspace 继承和多目标构建
当在一个 Cargo workspace 里管理多个相关的库/产品时,现在可以避免在多个库里使用相同的字段值了,比如相同的版本号,仓库链接,rust-version
。在更新的时候也可以更容易地保持这些信息地一致性。更多细节可以参考:
另外在构建多个目标地时候,现在可以直接传递多个 --target
选项给 cargo build
来一次性编译所有目标。也可以在 .cargo/config.toml
里设置一个 build.target
的 array 来改变默认构建时的对象。
稳定API && Others
更多稳定API列表和其它更新内容,请参考原文最后 stabilized-apis