Rust 新版解读 | 1.65 | 重点: 泛型关联类型,新绑定语法!
Rust 1.65 官方 release doc: Announcing Rust 1.65.0 | Rust Blog
通过 rustup 安装的同学可以使用以下命令升级到 1.65 版本:
$ rustup update stable
泛型关联类型 Generic associated types (GATs)
关联类型(associated types)里现在可以加上生命周期、类型、const泛型了,类似于:
#![allow(unused)] fn main() { trait Foo { type Bar<'x>; } }
三言两语说不清这个变化的好处,看几个例子来感受一下:
#![allow(unused)] fn main() { /// 一个类似于 `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>; } }
泛型关联类型十分通用,能够写出许多之前无法实现的模式。更多的信息可以参考下面的链接:
第一个对上面的例子进行了更深入的讨论,第二个讨论了一些已知的局限性。
更深入的阅读可以在关联类型的 nightly reference 和 原始 RFC(已经过去6.5年了!) 里找到。
let
- else
语法
新的 let
语法,尝试模式匹配,找不到匹配的情况下执行发散的 else
块。
#![allow(unused)] fn main() { let PATTERN: TYPE = EXPRESSION else { DIVERGING_CODE; }; }
常规的 let
语法仅能使用 irrefutable patterns
,直译为不可反驳的模式,也就是一定要匹配上。一般情况下都是单个变量绑定,也用在解开结构体,元组,数组等复合类型上。原先并不适用条件匹配,比如从枚举里确定枚举值。直到现在我们有了 let
- else
。这是 refutable pattern
,直译为可反驳的模式,能够像常规 let
一样匹配并绑定变量到周围范围内,在模式不匹配的时候执行发送的 else
(可以是 break
, return
, panic!
)。
#![allow(unused)] fn main() { 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
绑定来完成:
#![allow(unused)] fn main() { 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 可以直接给块语句添加标记来提前退出了,还可以携带返回值:
#![allow(unused)] fn main() { 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