每日见闻之Rust中的引用规则

规则一

所有权型变量的作用域是从它定义时开始到所属那层花括号结束。

代码示例

js 复制代码
fn main() {
    let mut a = 10u32;
    let b = &mut a;
    *b = 20;
    let c = &a;    
} //a的作用域到这里结束

规则二

引用型变量的作用域是从它定义起到它最后一次使用时结束。

代码示例

js 复制代码
fn main() {
    let mut a = 10u32;
    let b = &mut a;//b的作用域从这里开始
    *b = 20;//b的作用域到这里结束
    let c = &a;    
} //a的作用域到这里结束

规则三

一个所有权型变量的不可变引用可以同时存在多个,可以复制多份。

代码示例

js 复制代码
fn main() {
    let x = String::from("hello"); // 所有权变量 x
    
    // 创建多个不可变引用
    let r1 = &x; // 不可变引用 r1
    let r2 = &x; // 不可变引用 r2(同时存在,合法)
    let r3 = &x; // 不可变引用 r3(可创建任意多个)
    
    // 使用这些引用(均为只读)
    println!("r1: {}, r2: {}, r3: {}", r1, r2, r3);
    
    // 所有引用在作用域结束后自动释放,不影响原变量
    // x 的所有权仍在当前作用域内,未转移
}

规则四

一个所有权型变量的可变引用与不可变引用的作用域不能交叠,也可以说不能同时存在.

js 复制代码
fn main() {
    let mut a = 10u32;
    let c = &a;        // c作用域开始
    let b = &mut a; //b作用域开始
    *b = 20;//b作用域结束
  
    println!("{c}");//c作用域结束
}

不可变引用c的作用域包含了可变引用b的作用域。作用域重叠编译不通过

修正

js 复制代码
fn main() {
    let mut a = 10u32;
    let b = &mut a; //b作用域开始
    *b = 20;//b作用域结束
    let c = &a;        // c作用域开始
    println!("{c}");//c作用域结束
}

可变引用a的作用域跟不可变引用b作用域不重叠,编译通过。

规则五

某个时刻对某个所有权型变量只能存在一个可变引用,不能有超过一个可变借用同时存在,也可以说,对同一个所有权型变量的可变借用之间的作用域不能交叠

示例

js 复制代码
fn main() {
    let mut a = 10u32;
    let b = &mut a; //b的作用域开始
    *b = 20;
    let d = &mut a; //d的作用开始 结束
    
    println!("{b}");//b的作用域结束
}

可变引用b,d作用域重叠,编译不通过。简单说就是声明新的可变引用的时候,在他之前声明的可变引用不可以再使用。

规则六

在有借用存在的情况下,不能通过原所有权型变量对值进行更新。当借用完成后(借用的作用域结束后),物归原主,又可以使用所有权型变量对值做更新操作了

示例

js 复制代码
fn main() {
    let mut a = 10u32;
    let r1 = &mut a;
    a = 20;
    
    println!("{r1}");
}

在有可变引用r1的情况下,所有权变量修改值,编译不通过。简单说就是想要操作所有权变量,就要保证之前的所有引用在所有权变量操作之后不会再用到。

规则七

可变引用的再赋值,会执行移动操作。赋值后,原来的那个可变引用变量就不能用了。这有点类似于所有权的转移,因此一个所有权型变量的可变引用也具有所有权特征,它可以被理解为那个所有权变量的独家代理,具有排它性

示例

js 复制代码
fn main() {
    let mut a = 10u32;
    let r1 = &mut a;
    let r2 = r1;
     println!("{r1}");
    println!("{r2}");    // 打印r2
}

可变引入r1 赋值给r2之后,这里执行的是move操作,也就是说r1不能再使用了,打印r1编译不通过。

后记

用引用改进函数的定义

传递不可变引用到函数

js 复制代码
fn foo(s: &String) {
    println!("in fn foo: {s}");
}

fn main() {
    let s1 = String::from("I am a superman.");
    foo(&s1);    // 注意这里传的是字符串的引用 &s1
    println!("{s1}");    // 这里可以打印s1的值了
}

传递可变引用到函数

js 复制代码
fn foo(s: &mut String) {
    s.push_str(" You are batman.");
}

fn main() {
    let mut s1 = String::from("I am a superman.");
    println!("{s1}");
    foo(&mut s1);    // 注意这里传的是字符串的可变引用 &mut s1
    println!("{s1}");
}

最后大白话总结:只有不可变引用的时候,随便用。如果涉及到所有权变量修改值或者可变引用,那就要保证在声明新的引用的时候或者使用所有权变量修改值的时候,之前声明的引用不可以再用。

相关推荐
_李小白37 分钟前
【android opencv学习笔记】Day 17: 目标追踪(MeanShift)
android·opencv·学习
用户86022504674721 小时前
AI 分析头部APP系统优化框架
android
用户86022504674721 小时前
AI分析头部APP优化框架
android
2501_916007474 小时前
iOS开发中抓取HTTPS请求的完整解决方法与步骤详解
android·网络协议·ios·小程序·https·uni-app·iphone
lvronglee7 小时前
【数字图传第四步】Android App查看图传视频
android·音视频
90后的晨仔7 小时前
Android 程序入口与核心组件详解
android
90后的晨仔7 小时前
Kotlin 简介与开发环境搭建
android
BU摆烂会噶7 小时前
【LangGraph】House_Agent 实战(四):预定流程 —— 中断与人工干预
android·人工智能·python·langchain
AI玫瑰助手7 小时前
Python运算符:比较运算符(等于不等等于大于小于)与返回值
android·开发语言·python
new_dev8 小时前
Python实现Android自动化打包工具:加固、签名、多渠道一键完成
android·python·自动化