通过例子学习Rust--15.作用域规则
Rust-系列:
作用域规则
主要是针对所有权、借用、生命周期规范
RAII
- Rust中强制进行RAII资源获取即初始化 ,在任何对象离开作用域的时候会调用它的析构函数,因此不需要手动释放内存,避免了资源泄露 。
- 析构函数通过Drop 提供,自定义的类型需要自己实现drop trait,其余的自动实现了这种trait。
所有权和移动
- 因为变量要进习释放所用有的资源,因此只有一个所有者,因此就有了引用 这种方法。
- 指针指向堆地址,如果进行移动,这个时候之前的指针会失去作用,新的指针会拥有原来堆上的内存原来指针会失效 ,手动执行释放后,新的指针也不能访问。
- 而对于变量的移动,让两个变量拥有相同的值,两个变量是都可以访问的。
可变性
- 可变指针可以进行修改指针指向的内容,但是不可变指针不行。所有权 转移:由不可变指针->可变指针,会得到这样的结果。
部分移动
- 在对结构体进行解构的过程中,可以使用
ref
关键字进行绑定,绑定过ref
的参数属于是引用的参数。而没有标注的则是move
模式。
借用
- 借用
&T
的存在巧妙解决了所有权T
和使用中的问题。 - 编译器通过借用检查,保证了引用总是指向有效的对象,
存在引用指向对象的过程中,该对象不能够进行销毁
可变性
- 借用有两种形式:
&mut T
(可以允许读、写数据),&T
只能够读不能够写数据。 - 不能够可变的借用不可变对象,如果需要,先创建一个可变拷贝。
别名使用
数据允许多次不可变借用,但是有不可变借用的同时,不能使用可变借用
同一时间只允许有一次可变借用,当最后一次可变借用使用过后(通常是使用过println!
之后),才可以再次借用
ref模式
ref
相当于&
,不同点是ref
在左边,&
在右边,而在参数中基本相同。
生命周期
- 生命周期和作用域是不同的概念。
- 生命周期在结束的时候必须要保证它的引用已经结束,这部分由编译器检查。
显式标注
- 生命周期函数在使用的过程中:
1 | foo<'a, 'b> |
- 像是这种生命周期参数,则
foo
不能超出a、b中间任意一个生命周期 - 同样的,如果函数体内部有局部变量,这种局部变量的生命周期小于函数体,则不可将短生命周期的局部变量转换为长生命周期。
函数
- 生命周期有省略的情况,在这种情况之外:
- 任何引用都必须要有标注好的生命周期
- 任何被返回的引用要有和它输入量相同或者是静态类型的生命周期
- 引用的生命周期要大于函数体本身,不然没法返回(类似于上一句,但是一定要大于函数体本身,不然会产生悬空指针,是指引用输入的变量,而在形参上和函数体保持一致)
- 不能将局部变量返回,因为它的生命周期短于函数体本身:
1 | fn invalid_output<'a>() -> &'a String { &String::from("foo") } |
方法
- 方法标注和函数体类似。
trait
impl
块可能也有生命周期的标注
约束
- 泛型和生命周期相同,都可以使用约束。
:
字符意义为:
T: 'a:在 T 中的所有引用都必须比生命周期 'a 活得更长。
T: Trait + 'a:T 类型必须实现 Trait trait,并且在 T 中的所有引用都必须比 'a 活得更长。
1 | use std::fmt::Debug; // 用于约束的 trait。 |
强制转换
- 强制转换可以由编译器隐式推导,也可以通过声明不同生命周期的形式实现。
- 通常情况之下是由较长的生命周期转换为较短的生命周期。
static
- 'static是生命周期中最长的,它能够在整个程序运行过程中存在。它也可以被强制转换为一个更短的生命周期。
static生命周期的变量被保存在可执行文件的只读内存区。实现方法:
- 使用static声明常量
1 | static NUM: i32 = 18;//函数体之外 |
- 产生拥有&'static str类型的string字面量
省略
- 在某些普遍的状态之下rust可以省略生命周期的写法。可以在《Rust程序设计语言》中找到相关的解释。
Comment