Understanding Ownership
什么是所有权?
编程语言处理内存的方式:
- 通过垃圾回收机制管理内存
- 通过程序员手动分配和释放内存
- Rust通过所有权管理:编译器在编译时会根据一系列的规则进行检查
栈和堆
- 一个函数占用的数据大小是可计算(固定的)
- 可以确定数据大小时用栈,不确定数据大小时用堆
- 栈的效率比堆的高
- 堆分配内存需要消耗,需要计算分配, 使用栈上的数据可以无脑往前堆
- 访问堆上的数据比栈上的慢.取堆上的数据至少通过栈上的指针来获取(转跳两次)
堆:不确定的部分,容易出问题的部分
所有权规则解决的问题:管理堆上数据
- 跟踪哪部分代码使用堆上的数据
- 减少堆上重复数据的数量
- 清理堆上不在使用的数据
所有权规则
- Rust中的每一个值都有一个被称为其所有者(owner)的变量。
- 值有且只有一个所有者。
- 当所有者(变量)离开作用域,这个值将被丢弃。
变量作用域
String 类型
String内部:容量,长度,指针
特点:有数据在栈上,也有数据在堆上
内存与分配
- gc记录并清理不再使用的内存
- 手动申请和释放:
allocate
/free
- rust:数据变量在离开作用域后就被自动释放.本质上是在作用域结束的时候自动调用
drop
函数
C++的RAII(Resource Acquisition Is Initialization)全称资源获取即初始化https://zh.wikipedia.org/wiki/RAII
变量与数据交互的方式(一):移动
数据(堆上)的所有权从一个变量移动到另一个变量上
深拷贝和浅拷贝:是对有堆上的数据而言的,
Rust永远不会自动创建数据的"深拷贝",=
号只拷贝栈上的数据
变量与数据交互的方式(二):克隆
明确需要深拷贝:调用clone
函数
只在栈上的数据:拷贝
Copy
trait,如果一个类型实现了Copy
trait,这种类型的变量,能在赋值给新的变量之后仍然可用
区分哪些数据类型只存在于栈上;哪些数据类型既和栈相关,也和堆相关
所有权与函数
返回值与作用域
对于持有堆中数据的变量,除非所有权发生转移,不然,在他离开作用域的时候,会自动调用drop
函数清理调
所有权转移总结:
- 显示
=
号赋值的时候会转移 - 调用函数的时候会转移(有隐藏的
=
号赋值运算) - 函数调用返回时会转移
问题:有10个函数会使用到同一个数据,堆上的数据所有权在10个函数中轮流(转移)?
引用与借用
引用等同于取地址, 传引用等同于传地址,引用的本质就是指针
将获取引用作为函数参数称为 借用(borrowing)
借用没有所有权,在生命周期结束时,不会调用drop
函数清理堆上数据. 借的必需还回去
可变引用
通过引用去修改数据
- 同一作用域,不能同时拥有多个可变引用
- 可以同时有多个不可变引用
悬垂引用(Dangling References)
悬垂指针(dangling pointer):指向的数据地址,内存已经释放
在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域
引用的规则
- 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用
- 引用必须总是有效的
Slice 类型
没有所有权的数据类型:slice
&str
其它slice类型