规则一
所有权型变量的作用域是从它定义时开始到所属那层花括号结束。
代码示例
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}");
}
最后大白话总结:只有不可变引用的时候,随便用。如果涉及到所有权变量修改值或者可变引用,那就要保证在声明新的引用的时候或者使用所有权变量修改值的时候,之前声明的引用不可以再用。