RUST的 所有权,引用,借用,可变,不可变

我来总结 Rust 中所有权、引用、借用、可变、不可变的注意事项:

Rust 核心概念总结

1. 所有权(Ownership)

核心规则

  • 每个值都有一个所有者
  • 同一时间只能有一个所有者
  • 所有者离开作用域时,值被丢弃

注意事项

// ❌ 错误:所有权转移后不能使用原变量
let s1 = String::from("hello");
let s2 = s1;  // 所有权转移
// println!("{}", s1);  // 错误!s1 已失效
// ✅ 正确:使用克隆
let s1 = String::from("hello");
let s2 = s1.clone();  // 克隆,不转移所有权
println!("{}", s1);  // ✅ s1 仍然有效

关键点

  • 移动语义:赋值会转移所有权
  • Copy 类型:实现了 Copy trait 的类型赋值会复制而不是移动
  • 函数参数:传递参数会转移所有权
  • 返回值:函数返回值会转移所有权给调用者

2. 引用(References)

核心概念

  • 引用是借用值的方式
  • 不获取所有权
  • 必须始终有效

注意事项

// ❌ 错误:悬垂引用
fn dangle() -> &String {
    let s = String::from("hello");
    &s  // 错误!s 离开作用域后被释放
}
// ✅ 正确:返回所有权
fn no_dangle() -> String {
    let s = String::from("hello");
    s  // 返回所有权
}

关键点

  • 语法&T 表示引用
  • 解引用* 操作符访问引用指向的值
  • 生命周期:引用必须有效,不能指向已释放的内存

3. 借用(Borrowing)

核心规则

  • 同一时间只能有一个可变引用,或多个不可变引用
  • 引用必须始终有效
  • 可变和不可变引用不能同时存在

注意事项

// ❌ 错误:多个可变引用
let mut x = 5;
let r1 = &mut x;
let r2 = &mut x;  // 错误!
// ✅ 正确:作用域隔离
let mut x = 5;
{
    let r1 = &mut x;
} // r1 离开作用域
let r2 = &mut x;  // ✅ 可以

关键点

  • 借用检查器:编译时检查借用规则
  • 非词法作用域(NLL):引用可以在作用域结束前失效
  • 最后一次使用:引用最后一次使用后可以失效

4. 可变(Mutable)

核心概念

  • 可变变量:使用 mut 关键字
  • 可变引用:使用 &mut 语法
  • 允许修改:可以修改值或引用指向的值

注意事项

// ❌ 错误:修改不可变变量
let x = 5;
x = 10;  // 错误!

// ✅ 正确:使用 mut
let mut x = 5;
x = 10;  // ✅ 可以修改

关键点

  • 默认不可变:Rust 默认变量不可变
  • 显式可变:需要明确声明 mut
  • 可变引用&mut T 允许修改引用指向的值

5. 不可变(Immutable)

核心概念

  • 默认不可变:Rust 默认变量不可变
  • 不可变引用&T 不允许修改
  • 安全性:防止意外修改

注意事项

// ❌ 错误:修改不可变引用
let x = 5;
let r = &x;
*r = 10;  // 错误!
// ✅ 正确:使用可变引用
let mut x = 5;
let r = &mut x;
*r = 10;  // ✅ 可以修改

关键点

  • 默认安全:不可变性提供安全保障
  • 显式修改:需要明确声明可变性
  • 多线程安全:不可变性有助于并发安全

6. 综合注意事项

规则对比表

概念 语法 所有权 可修改性 注意事项
所有权 let x = value ✅ 获取 ❌ 不可变 转移后原变量失效
不可变引用 &T ❌ 借用 ❌ 不可修改 多个可存在
可变引用 &mut T ❌ 借用 ✅ 可修改 只能存在一个

常见错误

1. 所有权错误

// ❌ 使用已转移所有权的变量
let s1 = String::from("hello");
let s2 = s1;
println!("{}", s1);  // 错误!

2. 借用冲突

// ❌ 可变和不可变引用同时存在
let mut x = 5;
let r1 = &x;
let r2 = &mut x;  // 错误!

3. 悬垂引用

// ❌ 引用指向已释放的内存
fn bad() -> &String {
    let s = String::from("hello");
    &s  // 错误!
}

最佳实践

1. 明确所有权转移

let s1 = String::from("hello");
let s2 = s1;  // 明确知道 s1 已失效
// 使用 s2 而不是 s1

2. 合理使用引用

// 使用引用避免所有权转移
fn calculate_length(s: &String) -> usize {
    s.len()
}

3. 作用域隔离

// 使用作用域隔离借用
let mut x = 5;
{
    let r = &mut x;
    *r = 10;
}
// 可以再次使用 x

4. 生命周期标注

// 为复杂情况添加生命周期标注
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

7. 总结要点

  1. 所有权是基础:理解所有权是掌握 Rust 的关键
  2. 借用是工具:引用和借用是灵活使用值的工具
  3. 可变性是选择:默认不可变,需要修改时显式声明
  4. 编译器是朋友:借用检查器帮助发现错误
  5. 安全性优先:Rust 的设计优先考虑内存安全
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容