rust入坑之旅-引用

Scroll Down

引用和借用

什么是引用,在这个第二篇中提到了字符串,表现呢在于存放在stack上的ptr.在rust中回去引用使用的是& 符号 ,可以让你使用值但原来变量的所有权不发生move,与使用 & 引用相反的操作是 解引用(dereferencing),它使用解引用运算符,*
image
获取引用的过程如下所示 let zzz =String::from("hello"); let aaa=&zzz;这个就叫做借用。
image.png

和变量一样 引用也是默认不可变的 如果要通过引用修改原变量的值,则需要创建可变引用 使用mut关键字 可变引用只能应用于可变变量
image.png

fn test_change_reference() {
    let mut s1 = String::from("hello");

    change(&mut s1);
    // let r1 = &mut s;
    // let r2 = &mut s;
    // println!("{}, {}", r1, r2);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
    println!("The  is {}.", some_string);
}

可变引用有一个很大的限制:在同一时间只能有一个对某一特定数据的可变引用。这些代码编译时提示
cannot find valuesin this scop . help: a local variable with a similar name exists:这个限制的好处是 Rust 可以在编译时就避免数据竞争。有点类似在跑了go test -race XXXX

竞态条件

  • 两个或更多指针同时访问同一数据。

  • 至少有一个指针被用来写入数据。

  • 没有同步数据访问的机制。
    数据竞争会导致未定义行为,难以在运行时追踪,并且难以诊断和修复;Rust 避免了这种情况的发生,因为它甚至不会编译存在数据竞争的代码!

  • 可以使用大括号来创建一个新的作用域,以允许拥有多个可变引用,只是不能同时拥有


fn main() {
let mut s = String::from("hello");

{
   let r1 = &mut s;

} // r1 在这里离开了作用域,所以我们完全可以创建一个新的引用

let r2 = &mut s;
}

  • 同时使用可变与不可变引用
let mut s = String::from("hello");

let r1 = &s; // 没问题
let r2 = &s; // 没问题
let r3 = &mut s; // 有问题

println!("{}, {}, and {}", r1, r2, r3);

针对一个变量可以多次借用,因为变量和引用都不可变,针对可变变量的 不可变引用和可变引用的生命周期到可变引用出现的代码行。
悬垂引用(Dangling References)
在具有指针的语言中,很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针(dangling pointer),所谓悬垂指针是其指向的内存可能已经被分配给其它持有者。相比之下,在 Rust 中编译器确保引用永远也不会变成悬垂状态

fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &String {
    let s = String::from("hello");

    &s
}

image.png
这个方法主要是返回字符串 s 的引用,但是方法执行完毕 s 离开作用域并被丢弃。其内存被释放。
所以S的引用无法得到,是个无效的String Rust在编译阶段就抛出,

总结

  • 在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用。
  • 引用必须总是有效的。