|
|
@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
# Rust 新版解读 | 1.65 | 重点: 泛型关联类型,新绑定语法!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
> Rust 1.65 官方 release doc: [Announcing Rust 1.65.0 | Rust Blog](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
通过 [rustup](https://www.rust-lang.org/tools/install) 安装的同学可以使用以下命令升级到 1.65 版本:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
|
|
|
$ rustup update stable
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 泛型关联类型 Generic associated types (GATs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
关联类型(associated types)里现在可以加上生命周期、类型、const泛型了,类似于:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
trait Foo {
|
|
|
|
|
|
|
|
type Bar<'x>;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
三言两语说不清这个变化的好处,看几个例子来感受一下:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
/// 一个类似于 `Iterator` 的 trait ,可以借用 `Self`。
|
|
|
|
|
|
|
|
trait LendingIterator {
|
|
|
|
|
|
|
|
type Item<'a> where Self: 'a;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// 可以给智能指针类型,比如 `Rc` 和 `Arc` 实现的 trait,来实现指针类型的泛用性
|
|
|
|
|
|
|
|
trait PointerFamily {
|
|
|
|
|
|
|
|
type Pointer<T>: Deref<Target = T>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn new<T>(value: T) -> Self::Pointer<T>;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// 允许借用数组对象,对不需要连续存储数据的固定长度数组类型很有用
|
|
|
|
|
|
|
|
trait BorrowArray<T> {
|
|
|
|
|
|
|
|
type Array<'x, const N: usize> where Self: 'x;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn borrow_array<'a, const N: usize>(&'a self) -> Self::Array<'a, N>;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
泛型关联类型十分通用,能够写出许多之前无法实现的模式。更多的信息可以参考下面的链接:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* [2021/08/03/GAT稳定版本推进](https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html)
|
|
|
|
|
|
|
|
* [2022/10/28/GAT稳定版本发布公告](https://blog.rust-lang.org/2022/10/28/gats-stabilization.html)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
第一个对上面的例子进行了更深入的讨论,第二个讨论了一些已知的局限性。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
更深入的阅读可以在关联类型的 [nightly reference](https://doc.rust-lang.org/nightly/reference/items/associated-items.html#associated-types) 和 [原始 RFC](https://rust-lang.github.io/rfcs/1598-generic_associated_types.html)(已经过去6.5年了!) 里找到。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## `let` - `else` 语法
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
新的 `let` 语法,尝试模式匹配,找不到匹配的情况下执行发散的 `else` 块。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
let PATTERN: TYPE = EXPRESSION else {
|
|
|
|
|
|
|
|
DIVERGING_CODE;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
常规的 `let` 语法仅能使用 `irrefutable patterns`,直译为不可反驳的模式,也就是一定要匹配上。一般情况下都是单个变量绑定,也用在解开结构体,元组,数组等复合类型上。原先并不适用条件匹配,比如从枚举里确定枚举值。直到现在我们有了 `let` - `else`。这是 `refutable pattern`,直译为可反驳的模式,能够像常规 `let` 一样匹配并绑定变量到周围范围内,在模式不匹配的时候执行发送的 `else` (可以是 `break`, `return`, `panic!`)。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
fn get_count_item(s: &str) -> (u64, &str) {
|
|
|
|
|
|
|
|
let mut it = s.split(' ');
|
|
|
|
|
|
|
|
let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
|
|
|
|
|
|
|
|
panic!("Can't segment count item pair: '{s}'");
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let Ok(count) = u64::from_str(count_str) else {
|
|
|
|
|
|
|
|
panic!("Can't parse integer: '{count_str}'");
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
(count, item)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`if` - `else` 和 `match` 或者 `if let` 最大不一样的地方是变量绑定的范围,在此之前你需要多写一点重复的代码和一次外层的 `let` 绑定来完成:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
let (count_str, item) = match (it.next(), it.next()) {
|
|
|
|
|
|
|
|
(Some(count_str), Some(item)) => (count_str, item),
|
|
|
|
|
|
|
|
_ => panic!("Can't segment count item pair: '{s}'"),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let count = if let Ok(count) = u64::from_str(count_str) {
|
|
|
|
|
|
|
|
count
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
panic!("Can't parse integer: '{count_str}'");
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## `break` 跳出标记过的代码块
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
块表达式现在可以标记为 `break` 的目标,来达到提前终止块的目的。这听起来有点像 `goto` 语法,不过这并不是随意的跳转,只能从块里跳转到块末尾。这在之前已经可以用 `loop` 块来实现了,你可能大概率见过这种总是只执行一次的 `loop`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1.65 可以直接给块语句添加标记来提前退出了,还可以携带返回值:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
|
|
let result = 'block: {
|
|
|
|
|
|
|
|
do_thing();
|
|
|
|
|
|
|
|
if condition_not_met() {
|
|
|
|
|
|
|
|
break 'block 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
do_next_thing();
|
|
|
|
|
|
|
|
if condition_not_met() {
|
|
|
|
|
|
|
|
break 'block 2;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
do_last_thing();
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Others
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
其它更新细节,和稳定的API列表,参考[原Blog](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html)
|