Rust简聊 – 所有权的使用方式

一切权

界说

  1. 一切权:指Rust数据的运用权
  2. 一切者:代码里就用变量表示
  3. 效果域:变量有用(valid)的那个代码区间。简单来说就是它界说时地点的那个最里层的花括号括起的部分,从变量创立时开端,到花括号完毕的地方

解决问题

通过一切权系统管理内存数据,一方面有用解决数据的并发安全问题,一起编译器在编译时会依据一系列的规矩进行检查,避免将过错带到程序运行时

规矩

  1. Rust 中的每一个值都有一个 一切者owner)。
  2. 值在任一时间有且只要一个一切者。
  3. 当一切者(变量)脱离效果域,这个值将被丢弃 (一切权生命周期)

并不像 C 语言手动调用 free() 函数去释放堆中的资源

运用方法

fn main() {
    let s1 = "hello, world!".to_string();
    let s2 = s1;
    println!("{}", s2);
    println!("{}", s1);  //编译报错,
    //s1赋值后绑定了value的一切权, 将s1给s2赋值后,搬运value的一切权给s2,s1将不再可访问
}

Rust 供给了两种权限搬运方法,Move & Borrow。比方租车,没有车的一切权,租来开几天总是能够的。租的行为不发生一切权转变,只是获取暂时运用权,这种行为在 Rust 里叫 Borrow。如果想拥有车的一切权,能够直接购买,买完 4S 店就没有车的一切权了,这种行为在 Rust 里叫 Move

语句 对应含义
let b = a; a绑定的资源搬运给b,a不能再运用
let b = &a;  a绑定的资源借用给b运用,b只要资源的读权限,a仍然能再运用
let b = &mut a;  a绑定的资源借用给b运用,b有资源读写权限,a仍然能再运用
let mut b = &mut a;  a绑定的资源借用给b运用,b有资源读写权限,a仍然能再运用;一起b是可变的,可绑定到新的资源上面去

移动仍是复制?

  1. 默认做复制一切权(copy)的操作的有 7 种。

    1. 一切的整数类型,比方 u32;
    2. 布尔类型 bool;
    3. 浮点数类型,比方 f32、f64;
    4. 字符类型 char;
    5. 由以上类型组成的元组类型 tuple,如(i32, i32, char);
    6. 由以上类型组成的数组类型 array,如 [9; 100];
    7. 不可变引证类型 &。(&mut 是不支持copy的,因为一个变量在一个时间内只能有一个可变引证)。
  2. 其他的未实现copy trait的都是move

引证的分类

界说

  1. 不可变引证:&x是对变量 x 的不可变引证,不能够对值进行更改
  2. 可变引证:&mut x是对变量 x 的可变引证,能够对值进行更改

解决问题

  1. 不可变引证:是一种引证,为其他处理逻辑供给上文
  2. 可变引证:既是一种引证,又能够修正指向资源的内容

ex: 引证一个第三方库,它没有把一切权类型露出出来,但是确实又有更新其内部状况的需求,就需要可变引证

引证生命周期

引证型变量的效果域是从它界说起到它最后一次运用时完毕(必定小于等于一切者的生命周期,否则简单发生悬垂指针)

引证生命周期的关键点

界说

简单说:多个只读引证&交叉无问题,多个可写引证&mut交叉有问题,一个可写引证&mut和一个可读引证&有问题,直接操作一切权的值 = 加一个可写引证

  1. 一个一切权型变量的可变引证 &mut 与不可变引证 & 的效果域不能交叠

    1. 报错:cannot borrow a as mutable because it is also borrowed as immutable

  2. 同一个一切权型变量的可变借用 &mut 之间的效果域也不能交叠

    1. 报错:cannot borrow a as mutable more than once at a time

  3. 在有引证 &/&mut 的情况下,不能对一切权变量进行写操作,只能借用完结(物归原主)才干更新

    1. 报错:cannot assign to a because it is borrowed

  4. 能够一起有多个可读引证 &****

fn main() {
  let mut a = 10u32; 
  let c = &a;       //变量c的生命周期由此开端
  let b = &mut a;   //变量b的生命周期由此开端
  *b = 20;          //变量b的生命周期到此完毕
  println!("{c}");  //变量c的生命周期到此完毕
}
//因此b和c的生命周期发生了交叉,所以发生了编译报错

解决问题

避免多线程条件下读写竞赛导致的数据不一致性