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

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

相关推荐
还鮟3 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡4 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi004 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil6 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你6 小时前
Android View的绘制原理详解
android
移动开发者1号9 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号9 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best14 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk14 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭19 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin