MST

星途 面试题库

面试题:Rust所有权机制中的借用规则是怎样的

请详细阐述Rust所有权机制里借用的规则,包括但不限于同一作用域内可变借用和不可变借用的限制,以及这些规则如何保证内存安全。
24.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

借用规则概述

  1. 同一作用域内借用限制
    • 不可变借用:在同一作用域内,可以有多个不可变借用。这意味着多个变量可以同时以只读方式访问数据。例如:
    let s = String::from("hello");
    let r1 = &s;
    let r2 = &s;
    println!("{}, {}", r1, r2);
    
    这里r1r2都是对s的不可变借用,在同一作用域内可以共存。
    • 可变借用:在同一作用域内,只能有一个可变借用。可变借用允许对数据进行修改,为了避免数据竞争,Rust 规定同一时间只能有一个可变借用。例如:
    let mut s = String::from("hello");
    let r1 = &mut s;
    r1.push_str(", world");
    println!("{}", r1);
    
    如果在同一作用域内尝试创建第二个可变借用,编译器会报错。如:
    let mut s = String::from("hello");
    let r1 = &mut s;
    let r2 = &mut s; // 报错:不能在同一作用域内有多个可变借用
    
    • 不可变借用与可变借用共存限制:在同一作用域内,不可变借用和可变借用不能同时存在。这是因为可变借用允许修改数据,而不可变借用假设数据不会被修改,两者同时存在可能导致数据竞争。例如:
    let mut s = String::from("hello");
    let r1 = &s;
    let r2 = &mut s; // 报错:不能在有不可变借用时创建可变借用
    
  2. 借用的生命周期
    • 借用的生命周期必须足够短,以确保在借用结束后,借用的数据仍然有效。例如,不能返回一个指向局部变量的借用,因为局部变量在函数结束时会被销毁,借用的数据将无效。
    fn bad_get_ref() -> &String {
        let s = String::from("hello");
        &s // 报错:返回局部变量的借用,该变量在函数结束时会被销毁
    }
    
    正确的做法通常是将数据的所有权转移出去,而不是返回借用:
    fn get_string() -> String {
        let s = String::from("hello");
        s
    }
    

借用规则保证内存安全的原理

  1. 防止数据竞争:通过限制同一作用域内可变借用和不可变借用的数量,Rust 避免了多个指针同时修改数据(可变 - 可变数据竞争)或一个指针修改数据而其他指针同时读取数据(可变 - 不可变数据竞争)的情况。这种限制使得在编译时就能检测到可能的数据竞争,从而保证内存安全。
  2. 确保内存有效:借用的生命周期规则确保了借用的数据在其生命周期内不会被提前释放。编译器会检查借用的生命周期是否合理,避免悬空指针(指向已释放内存的指针)的产生,进一步保证了内存安全。

总之,Rust 的借用规则通过在编译时对借用进行严格检查,有效避免了常见的内存安全问题,如数据竞争和悬空指针,使得 Rust 程序在内存管理方面更加可靠。