5分钟速读之Rust权威指南(二十六)Drop

624 阅读2分钟

借助Drop trait在清理时运行代码

前面我们学过,变量只在变量所在的作用域有效,离开了作用域,如果没有转移所有权的话,将被清理,Drop trait允许我们在变量离开作用域时执行某些自定义操作。

实现Drop trait

我们可以为我们的自定义类型实现Drop trait:

#[derive(Debug)]
struct CustomSmartPointer {
  data: String,
}
impl Drop for CustomSmartPointer {
  fn drop(&mut self) {
    println!("删除带有数据的`{}`的CustomSmartPointer!", self.data);
  }
}

drop函数将在作用域结束时调用:

fn run() {
  let c = CustomSmartPointer { data: String::from("c") };
  let d = CustomSmartPointer { data: String::from("d") };
  println!("CustomSmartPointers创建完成.");

  // 下面rust将自动调用:(调用顺序是根据变量声明顺序,后进先出)
  d.drop()
  c.drop()
}
run();
// CustomSmartPointers创建完成.
// 删除带有数据的`d`的CustomSmartPointer!
// 删除带有数据的`c`的CustomSmartPointer!

有时需要提前清理一个值。例如使用智能指针来管理锁时,强制运行drop方法来提前释放锁,从而允许同一作用域内的其他代码来获取它。


除了rust可以按上面规则自动清理变量,我们也可以使用drop函数手动清理:

fn run() {
  let c = CustomSmartPointer { data: String::from("c") };
  let d = CustomSmartPointer { data: String::from("d") };
  println!("CustomSmartPointers创建完成.");

  // 使用std::mem::drop提前清理值
  use std::mem::drop;
  drop(c);

  // 清理之后将不能再使用
  // println!("{:?}", c); // 报错,c已经被清理
  println!("run函数调用完毕");
}
run();
// CustomSmartPointers创建完成.
// 删除带有数据的`c`的CustomSmartPointer!
// run函数调用完毕
// 删除带有数据的`d`的CustomSmartPointer!

由于c在run函数结束直接就已经被手动清理了,所以在run函数结束的时候只会清理d


有同学可能会想,是不是可以直接调用trait上的drop方法来清理数据呢?


fn run() {
  let c = CustomSmartPointer { data: String::from("c") };

  // 事实上rust并不允许手动调用Drop trait的drop方法
  c.drop() // 报错
}
run();

Drop trait主要用来清理一些副作用,比如当变量被清理时我们需要取消正在进行的网络请求,关闭正在打开的文件等。