RUST的引用和借用

    上一篇博客说到,移动是转交所有权,而克隆(Copy和Clone)是获得一个和旧值相同的新值的所有权)。

    那么如果我们想不转交所有权又对变量的值进行读取和修改(比如方法的传参问题,会改变所有权,即移动;或者读取和修改的不是原变量的值,即克隆),应该怎么做?

    RUST提供了引用和借用的机制。常规引用是一个指针类型,指向了对象存储的内存地址(和C++的指针比较像);获取变量的引用,则叫做借用。

    引用允许我们获得对值的使用权,但不是所有权。RUST中使用&获得变量的引用。

    C++需要通过*来访问指针指向的值,类似的,RUST也需要使用*来解引用,访问引用指向的值。不过RUST提供了自动解引用功能,大部分时候不需要显式解引用(一些情况如方法传参需要非引用的形参时还是要解引用的)。

struct Point {
    x: i32,
    y: i32,
}
fn main() {
    let p = Point { x: 10, y: 20 };
    println!("({}, {})", p.x, p.y);   //输出(10, 20)

    let q=&p;

    println!("({}, {})", (*q).x, (*q).y);  //输出(10, 20)
    println!("({}, {})", q.x, q.y);  //输出(10, 20)
}

    刚才说,引用允许获得对变量的使用权。

fn main() {
    let x = 5;
    let y=&x;   //y是x的引用
    println!("y: {}", y);  //输出y: 5
    println!("x: {}", x);  //输出x: 5
}

    但是上述代码中y只能读取x的值,而不能修改x的值,只实现了我们目标的一半。这又得说到不可变引用和可变引用的概念。

    不可变引用,即只能读取变量的值,不能对值进行修改(相当于C++中的const T*)。上面的例子中y就是一个不可变引用。

    可变引用,即既能读取变量的值,又能对值进行修改。

fn main() {
    let mut x = 5;
    let y=&mut x;

    (*y)+=1;

    println!("y: {}", y);  //输出y: 6
    println!("x: {}", x);  //输出x: 6
}

    上述代码中y是x的一个可变引用。使用&mut获取变量的可变引用。需要注意的是,被获取可变引用的变量必须是可变(mut)的。

    看到这里大家可能会想,这和C++的指针有啥区别吗?

    其实还是有的。在RUST中,引用有两条比较重要的限制:

1. 在相同作用域,同一个变量的可变引用只能存在一个。
2. 相同变量的可变引用和不可变引用不能同时存在。

    为什么要有这两条限制呢?原因是可以使Rust在编译期避免数据竞争。而数据竞争会导致未定义行为,这种行为很可能超出我们的预期,难以在运行时追踪,并且难以诊断和修复。
    先看第一条限制。

fn main() {
    //会报错,y1和y2的作用域重叠了
    let mut x = 5;
    let y1=&mut x;
    let y2=&mut x;

    println!("y1: {}", y1);//y1的作用域一直到这里结束
    println!("y2: {}", y2);  //y2的作用域一直到这里结束
}

    再看第二条限制。

fn main() {
    let mut x = 5;
    let y1= &x;
    let y2=&x;
    let y3=&mut x;  //会报错,因为已经有不可变引用了

    println!("y1: {}", y1);  //y1作用域到这里结束
    println!("y2: {}", y2);  //y2作用域到这里结束
    println!("y3: {}", y3); ////y3作用域到这里结束
}

    再说说引用的作用域。引用的作用域从引用的定义开始,到引用的最后一次使用结束。

fn main() {
    let mut x = 5;

    let y1= &x;  //y1的作用域在这里就结束了
    let y2=&x;   //y2的作用域在这里就结束了
    let y3=&mut x;  //不会报错
}

    在上述例子中,x的可变引用和不可变引用不会同时存在,所以不会报错。

posted @   nomore007  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示