Skip to content
Published at:

Understanding Ownership

什么是所有权?

编程语言处理内存的方式:

  • 通过垃圾回收机制管理内存
  • 通过程序员手动分配和释放内存
  • Rust通过所有权管理:编译器在编译时会根据一系列的规则进行检查

栈和堆

  • 一个函数占用的数据大小是可计算(固定的)
  • 可以确定数据大小时用栈,不确定数据大小时用堆
  • 栈的效率比堆的高
    • 堆分配内存需要消耗,需要计算分配, 使用栈上的数据可以无脑往前堆
    • 访问堆上的数据比栈上的慢.取堆上的数据至少通过栈上的指针来获取(转跳两次)

堆:不确定的部分,容易出问题的部分

所有权规则解决的问题:管理堆上数据

  • 跟踪哪部分代码使用堆上的数据
  • 减少堆上重复数据的数量
  • 清理堆上不在使用的数据

所有权规则

  1. Rust中的每一个值都有一个被称为其所有者(owner)的变量。
  2. 值有且只有一个所有者。
  3. 当所有者(变量)离开作用域,这个值将被丢弃。

变量作用域

String 类型

String内部:容量,长度,指针

特点:有数据在栈上,也有数据在堆上

内存与分配

  • gc记录并清理不再使用的内存
  • 手动申请和释放:allocate/free
  • rust:数据变量在离开作用域后就被自动释放.本质上是在作用域结束的时候自动调用drop函数

C++的RAII(Resource Acquisition Is Initialization)全称资源获取即初始化https://zh.wikipedia.org/wiki/RAII

变量与数据交互的方式(一):移动

数据(堆上)的所有权从一个变量移动到另一个变量上

深拷贝浅拷贝:是对有堆上的数据而言的,

Rust永远不会自动创建数据的"深拷贝",=号只拷贝栈上的数据

变量与数据交互的方式(二):克隆

明确需要深拷贝:调用clone函数

只在栈上的数据:拷贝

Copytrait,如果一个类型实现了Copytrait,这种类型的变量,能在赋值给新的变量之后仍然可用

区分哪些数据类型只存在于栈上;哪些数据类型既和栈相关,也和堆相关

所有权与函数

返回值与作用域

对于持有堆中数据的变量,除非所有权发生转移,不然,在他离开作用域的时候,会自动调用drop函数清理调

所有权转移总结:

  • 显示=号赋值的时候会转移
  • 调用函数的时候会转移(有隐藏的=号赋值运算)
  • 函数调用返回时会转移

问题:有10个函数会使用到同一个数据,堆上的数据所有权在10个函数中轮流(转移)?

引用与借用

引用等同于取地址, 传引用等同于传地址,引用的本质就是指针

将获取引用作为函数参数称为 借用(borrowing)

借用没有所有权,在生命周期结束时,不会调用drop函数清理堆上数据. 借的必需还回去

可变引用

通过引用去修改数据

  • 同一作用域,不能同时拥有多个可变引用
  • 可以同时有多个不可变引用

悬垂引用(Dangling References)

悬垂指针(dangling pointer):指向的数据地址,内存已经释放

在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域

引用的规则

  • 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用
  • 引用必须总是有效的

Slice 类型

没有所有权的数据类型:slice

&str

其它slice类型