关于 m12-lifecycle
m12-lifecycle 是面向 Rust 开发者的资源生命周期设计技能,帮助判断资源何时创建、如何使用及由谁清理,并将这些选择对应到 Rust 机制。
主要功能
- 01梳理资源成本与作用域
- 02比较 RAII、惰性初始化和资源池
- 03说明清理责任与错误处理
- 04提供生命周期模式模板
- 05列举常见资源管理错误
适用场景
- 01为数据库连接选择复用或创建策略
- 02设计离开作用域时自动清理
- 03处理惰性初始化和事务边界
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ actionbook/ rust-skills --skill m12-lifecycle安装后在 Claude Code 中输入/m12-lifecycle确认已加载。
详细介绍
资源生命周期
第 2 层:设计选择
核心问题
何时创建、使用和清理此资源?
在实现生命周期之前:
- 此资源的作用范围是什么?
- 谁负责清理?
- 出错时会发生什么?
生命周期模式 → 实现
| 模式 | 适用场景 | 实现方式 |
|---|---|---|
| RAII | 自动清理 | Drop trait |
| 延迟初始化 | 延后创建 | OnceLock、LazyLock |
| 池 | 复用开销较大的资源 | r2d2、deadpool |
| 守卫 | 限定作用范围的访问 | MutexGuard 模式 |
| 作用域 | 事务边界 | 自定义结构体 + Drop |
思考提示
设计生命周期之前:
-
资源成本是多少?
- 开销低 → 每次使用时创建
- 开销高 → 使用池或缓存
- 全局资源 → 延迟初始化的单例
-
作用范围是什么?
- 函数局部 → 栈分配
- 请求级 → 传递或提取
- 应用级 → static 或 Arc
-
错误该如何处理?
- 必须清理 → Drop
- 清理可选 → 显式关闭
- 清理可能失败 → 从 close 返回 Result
向上追溯 ↑
追溯到领域约束(第 3 层):
"How should I manage database connections?"
↑ Ask: What's the connection cost?
↑ Check: domain-* (latency requirements)
↑ Check: Infrastructure (connection limits)
| 问题 | 追溯至 | 要问的问题 |
|---|---|---|
| 连接池 | domain-* | 可接受的延迟是多少? |
| 资源限制 | domain-* | 基础设施有哪些约束? |
| 事务作用范围 | domain-* | 哪些操作必须是原子的? |
向下追溯 ↓
追溯到实现(第 1 层):
"Need automatic cleanup"
↓ m02-resource: Implement Drop
↓ m01-ownership: Clear owner for cleanup
"Need lazy initialization"
↓ m03-mutability: OnceLock for thread-safe
↓ m07-concurrency: LazyLock for sync
"Need connection pool"
↓ m07-concurrency: Thread-safe pool
↓ m02-resource: Arc for sharing
快速参考
| 模式 | 类型 | 使用场景 |
|---|---|---|
| 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) {
// Cleanup: remove temp file
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("config required")
})
}
常见错误
| 错误 | 原因 | 修复方法 |
|---|---|---|
| 资源泄漏 | 忘记实现 Drop | 实现 Drop 或 RAII 包装器 |
| 双重释放 | 手动管理内存 | 交由 Rust 处理 |
| 释放后使用 | 悬空引用 | 检查生命周期 |
| E0509:无法从 Drop 中移出值 | 移动所有权字段 | 使用 Option::take() |
| 池耗尽 | 资源未归还 | 确保 Drop 会归还资源 |
反模式
| 反模式 | 不足之处 | 更好的做法 |
|---|---|---|
| 手动清理 | 容易忘记 | RAII/Drop |
lazy_static! | 外部依赖 | std::sync::OnceLock |
| 全局可变状态 | 线程不安全 | OnceLock 或适当的同步机制 |
| 忘记关闭 | 资源泄漏 | 实现 Drop |
相关技能
| 适用场景 | 参见 |
|---|---|
| 智能指针 | m02-resource |
| 线程安全初始化 | m07-concurrency |
| 领域作用域 | m09-domain |
| 清理时出错 | m06-error-handling |
评论
支持 Markdown