引用和借用
& 符号就是引用, 允许使用值但不获取所有权
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("the length of {} is {}", s1, len);
fn calculate_length(s: &String) -> usize {
s.len()
} //变量 s 有效的作用域与函数参数的作用域一样,不过当引用离开作用域后并不丢弃它指向的数据,因为我们没有所有权。当函数使用引用而不是实际值作为参数,无需返回值来交还所有权,因为就不曾拥有所有权。
Xnip2021-05-26_16-08-12.jpg
将获取引用作为函数参数称为 借用(borrowing)
let s = String::from("hello");
change1(&s);
fn change1(some_string: &String) {
// 获取引用的值是借用 error
// some_string.push_str(", world")
}
可变引用
let mut s = String::from("hello");
change2(&mut s);
println!("s = {}", s);
fn change2(some_string: &mut String) {
some_string.push_str(", world");
}
可变引用有一个很大的限制:在特定作用域中的特定数据只能有一个可变引用。
let mut s = String::from("hello");
let r1 = &mut s;
// let r2 = &mut s; error 只能有一个可变引用
// println!("{}, {}", r1, r2);
目的: Rust 可以在编译时就避免数据竞争
1、两个或更多指针同时访问同一数据。
2、至少有一个指针被用来写入数据。
3、没有同步数据访问的机制。
可以通过大括号的创建一个作用域以允许拥有多个可变引用,只是不能 同时 拥有
let mut s = String::from("hello");
{
let r1 = &mut s;
// s.push_str("apple"); error s 已被借用
println!("r1 = {}", r1);
} // r1 在这里离开了作用域,所以我们完全可以创建一个新的引用
let r2 = &mut s;
println!("r2 = {}", r2);
注意一个引用的作用域从声明的地方开始一直持续到最后一次使用为止。
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
// 此位置之后 r1 和 r2 不再使用
let r3 = &mut s;
println!("r3 = {}", r3);
悬垂引用(Dangling References)
悬垂指针 = 内存释放了,指针没有释放
let reference_to_nothing = dangle();
fn dangle() -> &String {
// dangle 返回一个字符串的引用
let s = String::from("hello"); //s 是一个新字符串
&s // 返回字符串 s 的引用
} // 这里 s 离开作用域并被丢弃。其内存被释放。
// 危险!
引用的规则
1、在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用。
2、引用必须总是有效的。
网友评论