[ Rust笔记 十三] 内存安全-借用检查

两个概念:

  1. Alias的意思是“别名”​。如果一个变量可以通过多种Path来访问,那它们就可以互相看作alias。Alias意味着“共享”​,我们可以通过多个入口访问同一块内存。
  2. Mutation的意思是“改变”​。如果我们通过某个变量修改了一块内存,就是发生了mutation。Mutation意味着拥有“修改”权限,我们可以写入数据。

共享不可变,可变不共享

编译错误示例

通过不同的Path访问同一块内存p, *p1, * p2,所以它们存在“共享”​。而且它们都只有只读的权限,所以它们存在“共享”​,不存在“可变”​。因此它一定是安全的。

fn main() {//正常
    let i = 0;
    let p1 = & i;
    let p2 = & i;
    println! ("{} {} {}", i, p1, p2);
}

在存在只读借用的情况下,变量绑定i和p1已经互为alias,它们之间存在“共享”​,因此必须避免“可变”​。这段代码违反了“共享不可变”的原则。

fn main() {//报错
    let mut i = 0;
    let p1 = & i;
    i = 1;
}

因为这段代码中不存在“共享”​。在可变借用存在的时候,编译器认为原来的变量绑定i已经被冻结(frozen)​,不可通过i读写变量。此时有且仅有p1这一个入口可以读写变量。

fn main() {//正常
    let mut i = 0;
    let p1 = &mut i;
    *p1 = 1;
}

因为p1、p2都是可变借用,它们都指向了同一个变量,而且都有修改权限,这是Rust不允许的情况,因此这段代码无法编译通过。

 fn main() {//报错
    let mut i = 0;
    let p1 = &mut i;
    let p2 = &mut i;
}

&mut型借用也经常被称为“独占指针”, &型借用也经常被称为“共享指针”​。

内存不安全示例:修改枚举

enum StringOrInt {
    Str(String),
    Int(i64),
}

use std::fmt::Debug;
#[derive(Debug)]
enum StringOrInt {
        Str(String),
        Int(i64),
}
fn main() {//报错
    use StringOrInt::{Str, Int};
    let mut x = Str("Hello world".to_string());
    if let Str(ref insides) = x {
        x = Int(1);
        println! ("inside is {}, x says: {:? }", insides, x);
    }
}

我们用if let语法创建了一个指向内部String的指针,然后在此指针的生命周期内,再把x内部数据变成i64类型。这是典型的内存不安全的场景。

error: cannot assign to `x` because it is borrowed [E0506]

内存不安全示例:迭代器失效

如下代码不允许编译通过

fn main() {
    let mut arr = vec! ["ABC", "DEF", "GHI"];
    for item in &arr {
        arr.clear();
    }
}

因为Rust里面的for循环实质上是生成了一个迭代器,它一直持有一个指向容器的引用,在迭代器的生命周期内,任何对容器的修改都是无法编译通过的。

Rust的三大特点:一是快,二是内存安全,三是免除数据竞争。

内存不安全示例:悬空指针

fn main() {
    let mut arr : Vec<i32> = vec! [1,2,3,4,5];
    let p : &i32 = &arr[0];
    for i in 1..100 {
        arr.push(i);
    }
}


error: cannot borrow `arr` as mutable because it is also borrowed as immutable    

我们可以看到,​“mutation+alias”规则再次起了作用。在存在一个不可变引用的情况下,我们不能修改原来变量的值。写Rust代码的时候,经常会有这样的感觉:Rust编译器极其严格,甚至到了“不近人情”的地步。但是大部分时候却又发现,它指出来的问题的确是对我们编程有益的。对它使用越熟练,越觉得它是一个好帮手。