Rust所有权和借用规则示例

众所周知,所有权是Rust区别于其他语言的一大特色,只要代码满足了所有权规则,我们就不用担心内存的泄露的问题。
让代码在编译阶段就解决内存的问题,而不是在运行崩溃后再调试。

Rust中,所有权和借用的规则其实并不复杂,所有权有3条规则,借用只有2条规则。

所有权的规则

1. Rust中的每一个值都有一个对应的变量作为它的所有者

这个规则很好理解,比如下面的2个值 5hello分别属于变量 xy

fn main() {
    let x = 5;
    let y = String::from("hello");

    println!("x = {}, and y = {}", x, y);
}

2. 在同一时间内,值有且仅有一个所有者

比如下面的示例,当 x的值给了 y之后,x就不能再用了,值hello只能有一个所有者。

fn main() {
    let x = String::from("hello");
    let y = x;

    println!("x = {}, y = {}", x, y); // 这里会报错
}

3. 当所有者离开自己的作用域时,它持有的值就会被释放掉

fn main() {
    let x = String::from("hello");
    {
        let y = String::from("world");
        println!("{} {}", x, y);
    }
    println!("{} {}", x, y); // 这里会报错,获取不到 y,y已经释放了。
}

借用(引用)的规则

Rust中,引用和借用是一个意思,用借用能更准确的表达变量传递的含义。

1. 在任何一段给定的时间里,你要么只能拥有一个可变引用,要么只能拥有任意数量的不可变引用

yz 都拥有x的不可变借用。

fn main() {
    let x = 5;

    let y = &x;
    let z = &x;

    println!("y = {}, z = {}", y, z);
}

如果 y拥有可变借用,而 z拥有不可变借用,是不行的。

fn main() {
    let mut x = 5;

    let y = &mut x;
    let z = &x;   // 这里会报错,因为同一段时间内,既有x的不可变借用,又有可变借用

    println!("y = {}, z = {}", y, z);
}

2. 借用总是有效的

只要借用能编译,就说明借用是有效的,编译器会帮助我们确保借用都是有效的。

fn main() {
    let x = vec![1, 2, 3];
    lost(x);

    let y = &x;    // 这里编译会报错,因为 x 已经转移到 lost 函数中,在 main 中失效了
    println!("y = {:?}", y);
}

fn lost(x: Vec<i32>) {
    println!("lost: {:?}", x);
}

下面这样借用就不会报错,因为x只是借用给 no_lost函数。

fn main() {
    let x = vec![1, 2, 3];
    not_lost(&x);

    let y = &x;
    println!("y = {:?}", y);
}

fn not_lost(x: &Vec<i32>) {
    println!("lost: {:?}", x);
}

总结

所有权和借用是Rust确保内存安全使用的重要手段,上面的示例用最简单的方式展示了这些规则。

实际项目中,刚开始其实很难保证所有权和借用的规则,会经常遇到编译不了的情况。
但是,一旦养成了习惯,写代码时,脑中自然浮现变量在内存中的情况,自然就写出了内存安全的代码。

posted @ 2022-06-29 23:17  wang_yb  阅读(302)  评论(3编辑  收藏  举报