Rust入门-06-引用与借用

引用与借用

  • 引用是一种数据类型

  • & 符号就是引用

    • 允许使用值但不获取其所有权
  • 解引用dereferencing

    • 解引用运算符 *
fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);  // &s1 创建了一个指向 s1 的引用,但不拥有s1 
    
    println!("The length of '{}' is {}.", s1, len);

}

fn calculate_length(s: &String) -> usize {  //参数为&String,不是String
    s.len()
}      // s 离开了作用域。但因为它并不拥有引用值的所有权,所以什么也不会发生
  • s 为 s1 的引用,s 指向 s1 (指针?

借用(borrowing

  • 把引用作为函数参数的行为叫做借用

  • 默认不允许修改引用的值

    fn main() {
        let s = String::from("hello");
    
        change(&s);
    
    }
    
    fn change(some_string: &String) {
        some_string.push_str(", world");
    }
    

    该代码不能编译

可变引用

  • &mut string就为一个可变引用类型

    fn main() {
        let mut s = String::from("hello");
    
        change(&mut s);
    
    }
    
    fn change(some_string: &mut String) {
        some_string.push_str(", world");
    }
    

    该代码可以正常编译

  • 限制:在同一时间,对于某一特定的数据,只能有一个可变引用

    • 尝试创建两个可变引用的代码将会失败
    let mut s = String::from("hello");
    
    let r1 = &mut s;
    let r2 = &mut s;
        
    println!("{}, {}", r1, r2);
    

    该代码不能编译

  • 这个限制的好处是 Rust 可以在编译时就避免数据竞争(出现数据竞争的情况时,rust在编译时就会报错

    • 数据竞争data race)类似于竞态条件,它可由这三个行为造成:
      • 两个或更多指针同时访问同一数据
      • 至少有一个指针被用来写入数据
      • 没有同步数据访问的机制
  • 可以创建新的作用域(通过大括号),以允许非同时拥有多个可变引用

    let mut s = String::from("hello");
    
    {
        let r1 = &mut s;
     }    // r1 在这里离开了作用域,所以可以创建一个新的引用 r2
        
    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 在离开函数(离开作用域)后,就失效了
        &s                              //但对 s 的引用 &s 作为返回值返回了
                                        //即对 s 的引用 &s 就指向了一个被释放的内存地址
    }
    

    该代码不可以编译

引用的规则(总结

  • 在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用
  • 引用必须一直是有效的
posted @ 2022-04-29 20:11  ragworm  阅读(123)  评论(0)    收藏  举报