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

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

相关推荐
Libraeking6 小时前
破壁行动:在旧项目中丝滑嵌入 Compose(混合开发实战)
android·经验分享·android jetpack
市场部需要一个软件开发岗位7 小时前
JAVA开发常见安全问题:Cookie 中明文存储用户名、密码
android·java·安全
JMchen1238 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
crmscs9 小时前
剪映永久解锁版/电脑版永久会员VIP/安卓SVIP手机永久版下载
android·智能手机·电脑
localbob9 小时前
杀戮尖塔 v6 MOD整合版(Slay the Spire)安卓+PC端免安装中文版分享 卡牌肉鸽神作!杀戮尖塔中文版,电脑和手机都能玩!杀戮尖塔.exe 杀戮尖塔.apk
android·杀戮尖塔apk·杀戮尖塔exe·游戏分享
机建狂魔9 小时前
手机秒变电影机:Blackmagic Camera + LUT滤镜包的专业级视频解决方案
android·拍照·摄影·lut滤镜·拍摄·摄像·录像
hudawei9969 小时前
flutter和Android动画的对比
android·flutter·动画
lxysbly11 小时前
md模拟器安卓版带金手指2026
android
儿歌八万首12 小时前
硬核春节:用 Compose 打造“赛博鞭炮”
android·kotlin·compose·春节
消失的旧时光-194314 小时前
从 Kotlin 到 Dart:为什么 sealed 是处理「多种返回结果」的最佳方式?
android·开发语言·flutter·架构·kotlin·sealed