名称: m12-资源生命周期 描述: “用于设计资源生命周期时使用。关键词: RAII, Drop, 资源生命周期, 连接池, 惰性初始化, 连接池设计, 资源清理模式, 清理, 作用域, OnceCell, Lazy, once_cell, OnceLock, 事务, 会话管理, Drop何时被调用, 错误时清理, 守卫模式, 作用域守卫, 资源生命周期, 连接池, 惰性初始化, 资源清理, RAII 模式” 用户可调用: false
资源生命周期
第 2 层: 设计选择
核心问题
此资源应在何时创建、使用和清理?
设计生命周期前:
- 资源的范围是什么?
- 谁负责清理?
- 发生错误时如何处理?
生命周期模式 → 实现
| 模式 | 适用时机 | 实现方式 |
|---|---|---|
| RAII | 自动清理 | Drop trait |
| 惰性初始化 | 延迟创建 | OnceLock, LazyLock |
| 池化 | 复用昂贵资源 | r2d2, deadpool |
| 守卫 | 作用域内访问 | MutexGuard 模式 |
| 作用域 | 事务边界 | 自定义结构体 + Drop |
思考提示
设计生命周期前:
-
资源成本如何?
- 廉价 → 每次使用创建
- 昂贵 → 池化或缓存
- 全局 → 惰性单例
-
作用域是什么?
- 函数局部 → 栈分配
- 请求作用域 → 传递或提取
- 应用全局 → 静态或 Arc
-
错误如何处理?
- 必须清理 → Drop
- 清理可选 → 显式关闭
- 清理可能失败 → 从 close 返回 Result
向上追溯 ↑
追溯至领域约束(第 3 层):
"我应该如何管理数据库连接?"
↑ 询问:连接成本如何?
↑ 检查:domain-*(延迟要求)
↑ 检查:基础设施(连接限制)
| 问题 | 追溯至 | 询问 |
|---|---|---|
| 连接池 | domain-* | 可接受的延迟是多少? |
| 资源限制 | domain-* | 基础设施约束是什么? |
| 事务作用域 | domain-* | 哪些操作必须是原子的? |
向下追溯 ↓
追溯至实现(第 1 层):
"需要自动清理"
↓ m02-资源:实现 Drop
↓ m01-所有权:明确清理责任的所有者
"需要惰性初始化"
↓ m03-可变性:使用 OnceLock 实现线程安全
↓ m07-并发:使用 LazyLock 实现同步
"需要连接池"
↓ m07-并发:线程安全的池
↓ m02-资源:使用 Arc 共享
快速参考
| 模式 | 类型 | 使用场景 |
|---|---|---|
| RAII | Drop trait |
作用域退出时自动清理 |
| 惰性初始化 | OnceLock, LazyLock |
延迟初始化 |
| 池化 | r2d2, deadpool |
连接复用 |
| 守卫 | MutexGuard |
作用域锁释放 |
| 作用域 | 自定义结构体 | 事务边界 |
生命周期事件
| 事件 | Rust 机制 |
|---|---|
| 创建 | new(), Default |
| 惰性初始化 | OnceLock::get_or_init |
| 使用 | &self, &mut self |
| 清理 | Drop::drop() |
模式模板
RAII 守卫
struct FileGuard {
path: PathBuf,
_handle: File,
}
impl Drop for FileGuard {
fn drop(&mut self) {
// 清理:删除临时文件
let _ = std::fs::remove_file(&self.path);
}
}
惰性单例
use std::sync::OnceLock;
static CONFIG: OnceLock<Config> = OnceLock::new();
fn get_config() -> &'static Config {
CONFIG.get_or_init(|| {
Config::load().expect("配置必需")
})
}
常见错误
| 错误 | 原因 | 修复方法 |
|---|---|---|
| 资源泄漏 | 忘记实现 Drop | 实现 Drop 或 RAII 包装器 |
| 双重释放 | 手动管理内存 | 让 Rust 处理 |
| 释放后使用 | 悬垂引用 | 检查生命周期 |
| E0509 从 Drop 中移出 | 移动拥有字段 | 使用 Option::take() |
| 池耗尽 | 未归还资源 | 确保 Drop 会归还 |
反模式
| 反模式 | 为何不好 | 更好的做法 |
|---|---|---|
| 手动清理 | 容易忘记 | RAII/Drop |
lazy_static! |
外部依赖 | std::sync::OnceLock |
| 全局可变状态 | 线程不安全 | OnceLock 或适当的同步 |
| 忘记关闭 | 资源泄漏 | 实现 Drop |
相关技能
| 时机 | 参见 |
|---|---|
| 智能指针 | m02-资源 |
| 线程安全初始化 | m07-并发 |
| 领域作用域 | m09-领域 |
| 清理中的错误 | m06-错误处理 |