RUST——借用与引用
引用与借用
引用可以保证一个对象的引用作为参数而不是所有权
fn main() {
let s1=String::from("hello");
let len=cal_len(&s1);
println!("The length of {} is {}",s1,len);
}
fn cal_len(s: &String)->usize{
//s.push_str(", world");无法通过编译,因为属于借用
s.len()
}
示意图如下:
同时,不允许改变借用的值
如果想要改变引用的值,可以使用“可变引用”
例如:
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
可变引用存在一个限制,就是如果对一个变量具有可变引用,则不能再创建该变量的引用
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;//let r2=&s;
println!("{}, {}", r1, r2);
}
这一限制以一种非常小心谨慎的方式允许可变性,防止同一时间对同一数据存在多个可变引用。新 Rustacean 们经常难以适应这一点,因为大部分语言中变量任何时候都是可变的。这个限制的好处是 Rust 可以在编译时就避免数据竞争。数据竞争(data race)类似于竞态条件,它可由这三个行为造成:
- 两个或更多指针同时访问同一数据。
- 至少有一个指针被用来写入数据。
- 没有同步数据访问的机制。
数据竞争会导致未定义行为,难以在运行时追踪,并且难以诊断和修复;Rust 避免了这种情况的发生,因为它甚至不会编译存在数据竞争的代码
但是多个不可变引用是可以的
fn main() {
let mut s = String::from("hello");
let r1 = &s; // 没问题
let r2 = &s; // 没问题
println!("{} and {}", r1, r2);
// 此位置之后 r1 和 r2 不再使用
let r3 = &mut s; // 没问题
println!("{}", r3);
}
悬垂引用
在具有指针的语言中,很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针(dangling pointer),所谓悬垂指针是其指向的内存可能已经被分配给其它持有者。相比之下,在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域。
RUST会在编译的阶段阻止悬垂引用的出现,比如下面这段代码运行时会报错
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
//错误
&s
}
修复bug的方式是将最后一行&s
改变成s
,相当于传回去所有权,因为传的是所有权,所以作用域内drop就不起作用了
总结引用
在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用。
引用必须总是有效的
本文来自博客园,作者:理想国的糕,转载请注明原文链接:https://www.cnblogs.com/SaltyCheese/p/17308891.html嗷~