Rust Drop 与 RAII

离开作用域时 Drop 释放资源;RAII 把获取与释放绑定到生命周期;与 defer 思维对照。

#type / concept #status / growing #tech / dev #resource / rust

[!info] 关联笔记

Rust Drop 与 RAII

这个概念为什么出现

文件句柄、锁、内存、socket 都需要成对获取/释放
Rust 用所有权 + Drop trait 实现 RAII:所有者结束生命时自动清理,减少“忘记 close”。

[!abstract] 一句话理解 实现 Drop 的类型在离开作用域(或显式 drop)时运行析构逻辑;RAII 意味着资源寿命等于拥有者的寿命。

最小可运行示例

场景:临时会话令牌——离开作用域自动作废日志

鉴权中间层发一个短命 SessionGuard,结束时必须记“released”,即使中间有错误返回。

// 业务意图:模拟获取/释放会话资源。
// 教学点:自定义 Drop;作用域结束自动调用;提前 return 也触发。

struct SessionGuard {
    user_id: u64,
}

impl SessionGuard {
    fn acquire(user_id: u64) -> Self {
        println!("acquire user={user_id}");
        Self { user_id }
    }
}

impl Drop for SessionGuard {
    fn drop(&mut self) {
        println!("release user={}", self.user_id);
    }
}

fn handle(user_id: u64, fail: bool) -> Result<(), String> {
    let _guard = SessionGuard::acquire(user_id);
    if fail {
        return Err("biz error".into()); // drop 仍会发生
    }
    println!("handle ok");
    Ok(())
}

fn main() {
    let _ = handle(7, true);
    let _ = handle(8, false);
}

建议运行:cargo run

期望输出:

acquire user=7
release user=7
acquire user=8
handle ok
release user=8

结合场景再看三个关注点

  1. 错误返回不泄漏“释放日志”
  2. 无需 finally 样板(对比部分语言)
  3. 锁的 Guard 同一模式

核心概念与准确模型

pub trait Drop {
    fn drop(&mut self);
}
  • 不能显式调用 Drop::drop;用 std::mem::drop(value) 提前结束所有权
  • 字段 drop 顺序:通常按声明逆序(实现细节以 Reference 为准)
  • Copy 类型不实现 Drop

设计动机

  • 异常/错误路径也要释放
  • 把清理与类型绑定,而不是靠程序员记忆
  • 零成本常见路径

边界与误区

  • Drop 中恐慌会触发双重 panic 中止路径,保持析构简单
  • 循环引用(Rc)可能导致无法 drop,需 Weak
  • 异步取消与 drop 交互需小心

[!warning] 常见误区:假设 drop 在任意时刻立刻回收 OS 资源 缓冲 flush 失败等边界要查具体类型文档。

工程实践

  1. 资源类型暴露 guard
  2. 析构逻辑保持简短无失败敏感
  3. 需要手动提前释放就 drop(guard)
  4. 与错误处理组合:成功路径与失败路径同一清理

本节总结

  • Drop = 析构钩子
  • RAII = 资源=所有权寿命
  • 错误路径同样安全清理

自测题

  1. 为什么 CopyDrop 互斥?
  2. mem::drop 做什么?
参考答案
  1. Copy 暗示简单按位复制,不该有特殊清理。
  2. 把值移入函数并立刻结束其生命周期以触发 drop。

延伸阅读与资料来源

资料类型支撑内容
The Book — Drop官方书Drop
std::ops::Drop标准库trait
RAII (cppreference 概念对照)概念RAII 思想
创建于 2026/7/15 更新于 2026/7/15