侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

理解Rust中的所有权和借用

2025-12-8 / 0 评论 / 4 阅读

题目

理解Rust中的所有权和借用

信息

  • 类型:问答
  • 难度:⭐⭐

考点

所有权系统,借用规则,可变引用

快速回答

Rust的所有权系统通过三条核心规则保证内存安全:

  • 每个值有且只有一个所有者
  • 值在所有者离开作用域时自动释放
  • 可通过引用(&T)借用值,但同一作用域内:
    • 允许存在多个不可变引用
    • 或仅一个可变引用(&mut T)
    • 不可同时存在可变和不可变引用
## 解析

原理说明

Rust的所有权系统在编译期强制执行内存安全规则,无需垃圾回收。核心机制包括:

  • 所有权转移:赋值或传参时默认移动(move)语义,原变量失效
  • 借用(Borrowing):通过引用临时访问数据,不获取所有权
  • 生命周期:编译器验证引用的有效性,防止悬垂指针

代码示例

// 所有权转移示例
let s1 = String::from("hello");
let s2 = s1;  // s1的所有权转移到s2
// println!("{}", s1);  // 错误!s1已失效

// 合法借用示例
let mut s = String::from("rust");
{
    let r1 = &s;      // 不可变借用
    let r2 = &s;      // 允许多个不可变借用
    println!("{}, {}", r1, r2);
} // r1,r2离开作用域

let r3 = &mut s;     // 可变借用
r3.push_str("!");   // 修改数据
// let r4 = &s;       // 错误!已有可变借用时禁止不可变借用

最佳实践

  • 优先使用不可变引用(&T)保证并发安全
  • 缩小可变引用的作用域:
    let mut data = vec![1,2,3];
    // 正确做法:用花括号限制作用域
    {
        let ref_mut = &mut data;
        ref_mut.push(4);
    }
    let ref_imm = &data;  // 可变引用离开作用域后可创建不可变引用
  • 对Copy类型(如i32)使用克隆而非引用

常见错误

  • 错误1:违反借用规则
    let mut s = String::new();
    let r1 = &mut s;
    let r2 = &mut s; // 编译错误:不能多次可变借用
  • 错误2:返回局部变量引用
    fn dangling() -> &String {
        let s = String::from("error");
        &s  // 错误!s离开作用域被释放
    }
  • 错误3:迭代器失效
    let mut vec = vec![1,2,3];
    for item in &vec {
        vec.push(*item); // 错误!循环中同时持有不可变和可变借用
    }

扩展知识

  • 内部可变性:通过Cell/RefCell在不可变引用下修改数据
  • 生命周期标注:解决跨作用域引用的有效性,如fn longest<'a>(x: &'a str, y: &'a str) -> &'a str
  • Arc<Mutex<T>>:线程间共享可变数据的标准方案
  • NLL(Non-Lexical Lifetimes):Rust 2018起引用的作用域精确到最后一次使用而非作用域结束