跳到主要内容

Drop trait 与析构

问题

Rust 的 Drop trait 如何工作?析构顺序是怎样的?

答案

Drop trait

struct Resource {
name: String,
}

impl Drop for Resource {
fn drop(&mut self) {
println!("释放资源: {}", self.name);
}
}

fn main() {
let a = Resource { name: "A".into() };
let b = Resource { name: "B".into() };
} // 析构顺序:B → A(后声明先析构,类似栈的 LIFO)

析构顺序规则

  1. 局部变量:按声明的逆序析构
  2. 结构体字段:按声明的顺序析构
  3. 元组:按字段顺序析构
  4. 闭包捕获:按捕获顺序析构
struct S {
first: Resource, // 先析构
second: Resource, // 后析构
}
// 字段按声明顺序 drop:first → second

手动 drop

fn main() {
let lock = Mutex::new(42);
let guard = lock.lock().unwrap();
// 提前释放锁
drop(guard); // 显式调用 drop()
// 此后锁已释放,其他线程可以获取
}
警告

不能直接调用 value.drop(),必须用 std::mem::drop(value)drop(value)。编译器禁止显式调用 Drop::drop 方法(避免 double-free)。

ManuallyDrop

控制是否自动析构:

use std::mem::ManuallyDrop;

let mut data = ManuallyDrop::new(String::from("hello"));
// 不会自动 drop
// 手动决定何时释放
unsafe { ManuallyDrop::drop(&mut data); }

常见面试问题

Q1: Drop 和 Copy 为什么不能共存?

答案

Copy 表示值可以按位复制。如果类型实现了 Drop(有自定义清理逻辑),按位复制会导致两个值持有相同资源,drop 时发生 double-free。所以编译器禁止同时实现 CopyDrop

Q2: drop(x){ x; } 有区别吗?

答案

drop() 的实现就是 fn drop<T>(_: T) {}——接收所有权然后什么都不做,值在函数结束时被析构。{ x; }x 在块结束时析构。效果相同。

Q3: 析构可以失败吗?

答案

Drop::drop 返回 (),没有办法报告错误。如果需要可失败的清理(如刷新缓冲区),应该提供一个显式的 close() 方法,在 drop 中只做最后的兜底清理。

相关链接