《Rust 语言圣经》高阶部分阅读笔记
输入“/”快速插入
《Rust 语言圣经》高阶部分阅读笔记
2023年11月26日创建
15
73
0
以下是
《Rust 语言圣经》高阶部分
的阅读笔记(👷施工中)
注意:因内容较多,涉及代码基本有折叠,阅读时可手动展开。
1.
生命周期
•
编译器无法明确其生命周期的情况下,则需要手动进行标注,以下为常见的例子
◦
例子1:函数参数的默认生命周期,导致入参的可变性的生命周期被持续
◦
例子2:编译器的判断给借用安排了较大作用域,而导致后续借用失败
•
不安全代码(
unsafe
)经常会凭空产生引用或生命周期,而这些生命周期被称为是
无界(unbound)
•
生命周期也有
约束语法
,与特征约束类似,通过形如
'a: 'b
的语法来说明两个生命周期的长短关系
•
函数闭包
与方法的生命周期消除规则不同,其生命周期分散在参数和闭包函数体中(因无确切返回值签名)
•
引用的生命周期在 1.31 版本引入
NLL
后变成:
引用的生命周期从借用处开始,一直持续到最后一次使用的地方
•
除了基础的生命周期消除规则外,后续演化出的常见规则有 impl 块消除、类型生命周期约束消除
1.1
&'static 和 T:'static
•
&'static T
:
指向 T 的不可变引用
,其引用可被安全地无期限地持有,甚至可以直到程序结束
◦
这只有在 T 自身不可变且保证,在引用创建后不会被 move 时才有可能
◦
T 并不需要在编译时创建,我们可以以内存泄漏为代价,在运行时动态创建随机数据,并返回其 'static 引用
•
T: 'static
:
T 可以被安全地无期限地持有
,甚至可以直到程序结束
◦
T: 'static
同时包含
&'static T
和所有权类型
,如 String, Vec 等
◦
数据的所有者保证,只要自身还持有数据的所有权,数据就不会失效
◦
T: 'static
应当视为“T 满足 'static 生命周期约束” 而非 “T 有着 'static 生命周期”
•
代码示例
2.
函数式编程
2.1
闭包 Closure
•
闭包是一种匿名函数,可赋值给
变量
或
作为
参数
传递,
且
不同于函数
,
允许捕获
调用者作用域中的值
•
闭包由于不会作为 API 对外提供,因此可利用编译器的类型推导能力,做到
可不标注参数和返回值类型
◦
注意它也不是泛型,当编译器推导出一种类型后,则会
一直使用该类型
•
闭包可作为
一种类型被标注
,可利用 Fn 系列特征和特征约束来进行闭包的限制
•
当闭包从作用域捕获值时,会分配内存去存储该值,从而造成
额外的内存分配
Rust
fn main() {
let x = 4;
let equal_to_x = |z| z == x;
let y = 4;
assert!(equal_to_x(y));
}
•
闭包捕获变量有三种途径,恰好对应函数参数的三种传入方式:
转移所有权、可变借用、不可变借用,而相应的 Fn 特征也有三种
◦
FnOnce
:
转移捕获变量的所有权
,也说明该闭包只能运行一次,若类型实现 Copy 特征则不会转移
◦
FnMut
:
以可变借用的方式捕获环境值
,能够修改该值
◦
Fn
:
以不可变借用的方式捕获环境值
•
闭包实现的 Fn 特征取决于该闭包
如何使用被捕获的变量
,而不是取决于闭包如何捕获(如
move
)它们
•
闭包
可实现多种 Fn 特征
,且三种 Fn 特征的关系规则如下
•
当闭包作为函数返回值时,无法直接推断闭包特征的真实类型,需要
使用
impl Trait
来指定类型
2.2
迭代器 Iterator
•
迭代器和 for 循环的区别在于
是否通过索引来访问集合
•
实现
IntoIterator
特征可通过 for 语法糖
转换为迭代器
,如数组或数值序列等
•
Rust 中
迭代器是惰性的
,即使用前不会有任何的性能损耗,编译器自带的优化让性能表现无需担忧
•
迭代器都实现了特征
Interator
,其中可通过
next
方法依次
取出迭代器中的元素
,且
返回值是 Option 类型
◦
for 循环就是不断调用
next
方法来获取迭代器中的元素,且
next
方法对迭代器的遍历是消耗性的
◦
可通过实现
Interator
特征来自定义迭代器,必须实现
new
和
next
方法,同时也有默认实现的其他方法
•
在
IntoIterator
特征中可使用
into_iter|iter|iter_mut
方法将类型转换为迭代器,且前面方法依次对应针对获取类型值的
转移所有权、不可变借用和可变借用
•
Iterator
和
IntoIterator
的区别在于,前者为
迭代器特征
,后者是若类型实现特征可通过
方法转为迭代器