|
|
@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
# Rust 新版解读 | 1.64 | 重点: `IntoFuture` , Cargo 优化
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
> Rust 1.64 官方 release doc: [Announcing Rust 1.64.0 | Rust Blog](https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
通过 [rustup](https://www.rust-lang.org/tools/install) 安装的同学可以使用以下命令升级到 1.64 版本:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
|
|
|
$ rustup update stable
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 使用 `IntoFuture` 增强 `.await`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1.64 稳定了 `IntoFuture` trait,不同于用在 `for ... in ...` 的 `IntoIterator` trait,`IntoFuture` 增强了 `.awiat` 关键字。现在 `.await` 可以 await 除了 futures 外,还可以 await 任何实现了 `IntoFuture` trait 并经此转换成 `Future` 的对象。这可以让你的 api 对用户更加优化。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
举一个用在网络存储供应端的例子:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
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> { ... }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
通常地使用方法可能类似如下代码:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
let response = StorageRequest::new() // 1. 实例化
|
|
|
|
|
|
|
|
.set_debug(true) // 2. 设置一些选项
|
|
|
|
|
|
|
|
.send() // 3. 构造 future
|
|
|
|
|
|
|
|
.await?; // 4. 执行 future ,传递 error
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
这个代码已经不错了,不过 1.64 后可以做的更好。使用 `IntoFuture` ,把第三步的 “构造 future ” 和 第四步的 “执行 future ” 合并到一个步骤里:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
``` RUST
|
|
|
|
|
|
|
|
let response = StorageRequest::new() // 1. 实例化
|
|
|
|
|
|
|
|
.set_debug(true) // 2. 设置一些选项
|
|
|
|
|
|
|
|
.await?; // 3. 构造并执行 future ,传递 error
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
想要实现上面的效果,我们需要给 `StorageRequest` 实现 `IntoFuture` trait。`IntoFuture` 需要确定好要返回的 future,可以用下面的代码来实现:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
``` rust
|
|
|
|
|
|
|
|
// 首先需要引入一些必须的类型
|
|
|
|
|
|
|
|
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](https://rust-lang.github.io/impl-trait-initiative/explainer/tait.html),来简化定义 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](https://rust-lang.github.io/rustup/concepts/components.html) 来安装:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
|
|
|
rustup component add rust-analyzer
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
目前,使用 rustup 安装的版本,需要这样启用:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
|
|
|
rustup run stable rust-analyzer
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
下一次 rustup 的发布本把会提供一个内置的代理,来运行对应版本的 rust-analyzer 。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Cargo 优化,workspace 继承和多目标构建
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
当在一个 Cargo workspace 里管理多个相关的库/产品时,现在可以避免在多个库里使用相同的字段值了,比如相同的版本号,仓库链接,`rust-version`。在更新的时候也可以更容易地保持这些信息地一致性。更多细节可以参考:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* [workspace.package](https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table)
|
|
|
|
|
|
|
|
* [workspace.dependencies](https://doc.rust-lang.org/cargo/reference/workspaces.html#the-dependencies-table)
|
|
|
|
|
|
|
|
* ["inheriting a dependency from a workspace"](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#inheriting-a-dependency-from-a-workspace)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
另外在构建多个目标地时候,现在可以直接传递多个 `--target` 选项给 `cargo build` 来一次性编译所有目标。也可以在 `.cargo/config.toml` 里设置一个 `build.target` 的 array 来改变默认构建时的对象。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 稳定API && Others
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
更多稳定API列表和其它更新内容,请参考原文最后 [stabilized-apis](https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#stabilized-apis)
|