847 字
4 分钟
所有权

核心定义
所有权是 Rust 的核心内存管理机制,基于三条规则:
- 每个值有唯一所有者(变量)
- 值离开作用域时自动释放
- 所有权可通过移动(move)转移(如赋值/传参),或通过借用(borrow)临时共享 此机制在编译期消除数据竞争和内存错误(空指针/内存泄漏),无需垃圾回收。
工作原理
编译器跟踪每个值的生命周期:
- 移动语义:当值赋给新变量或传入函数,所有权转移(原变量失效)
- 借用检查:通过引用(
&T
/&mut T
)临时访问值,强制执行读写锁规则(N写 or 1读) - 作用域结束:所有者离开作用域时,自动调用
drop
释放内存
flowchart TD A[创建值 owner = String::new] --> B{操作类型} B -->|移动| C[新所有者 new_owner = owner] B -->|借用| D[创建引用 ref = &owner] C & D --> E[离开作用域] E -->|移动后| F[原owner无效] E -->|借用的值| G[值被释放]
关键点
- 移动而非复制:未实现
Copy
的类型(如String
)赋值时转移所有权 - 借用规则:
- 任意数量不可变引用(
&T
) - 唯一可变引用(
&mut T
)
- 任意数量不可变引用(
- 函数交互:传参转移所有权,返回值可返回所有权
- 克隆显式复制:
clone()
深拷贝数据 - 解构移动:模式匹配(
match
)可能转移字段所有权
常见误区
- 意外移动:循环中使用集合迭代器(
for x in vec
转移所有权) - 悬垂引用:返回局部变量引用(
fn f() -> &str { &String::new() }
) - 误用克隆:过度使用
clone()
导致性能下降 - 部分移动:解构未实现
Copy
的结构体(如let p = Point { x: String::new(), y: 1 }; let x = p.x;
后p.y
仍可用但p
部分失效) - 借用冲突:同时创建可变和不可变引用(
let r1 = &s; let r2 = &mut s;
)
应用场景
场景 | 示例 | 所有权作用 |
---|---|---|
避免数据竞争 | let mut s = String::new(); let r1 = &s; let r2 = &s; | 允许多读 |
安全资源管理 | File::open("a.txt") → 离开作用域自动关闭文件 | 替换 try-finally 块 |
高效内存传递 | fn take(s: String) { ... } take(my_string) | 移动而非深拷贝 |
智能指针实现 | Box::new() / Rc::new() | 明确堆内存所有权 |
零成本抽象 | 自定义类型实现 Drop trait | 释放时执行自定义逻辑(如网络连接) |
关联知识
- 生命周期(Lifetimes):编译器验证引用有效性的辅助标记
- 借用检查器(Borrow Checker):在编译期强制执行所有权规则
- 智能指针:
Box<T>
:独占堆内存所有权Rc<T>
/Arc<T>
:共享所有权(引用计数)RefCell<T>
:运行时借用检查
- Copy 与 Clone:
Copy
:位复制(编译器自动处理,如i32
)Clone
:显式深拷贝(需调用.clone()
)
- 模式匹配:解构时可能转移所有权(尤其未实现
Copy
的类型) - 并发安全:所有权系统是实现
Send
/Sync
的基础 - 错误处理:所有权转移与
?
运算符交互(如File::open?
)
💡 黄金法则:
移动后失效:值被移动后原始绑定立即失效 引用不拥有:借用(引用)不获取所有权,仅临时访问 作用域即生命周期:变量离开作用域时值被释放 优先让编译器报错指导修复,而非强行
clone()
!