每日见闻之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}");
}

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

相关推荐
CYRUS_STUDIO2 小时前
深入 Android syscall 实现:内联汇编系统调用 + NDK 汇编构建
android·操作系统·汇编语言
死也不注释3 小时前
【第一章编辑器开发基础第一节绘制编辑器元素_6滑动条控件(6/7)】
android·编辑器
程序员JerrySUN4 小时前
Linux 文件系统实现层详解:原理、结构与驱动衔接
android·linux·运维·数据库·redis·嵌入式硬件
2501_916013745 小时前
iOS 加固工具使用经验与 App 安全交付流程的实战分享
android·ios·小程序·https·uni-app·iphone·webview
南棱笑笑生5 小时前
20250715给荣品RD-RK3588开发板刷Android14时打开USB鼠标
android·计算机外设
hy.z_7777 小时前
【数据结构】反射、枚举 和 lambda表达式
android·java·数据结构
幻雨様7 小时前
UE5多人MOBA+GAS 20、添加眩晕
android·ue5
没有了遇见8 小时前
开源库 XPopup 资源 ID 异常修复:从发现 BUG 到本地 AAR 部署全流程
android
雮尘8 小时前
一文读懂 Android 屏幕适配:从基础到实践
android·前端
用户2018792831678 小时前
浅谈焦点冲突导致异常背景色的机制
android