通常情况下,Rust的destructor会自动地销毁程序不再需要的变量,通常[1]也就是变量ownership移出其scope时进行这项工作。
但是你可以实现std::ops::Droptrait来自定义这项工作的执行细节。

根据Drop的文档:

This destructor consists of two components:

  • A call to Drop::drop for that value, if this special Drop trait is implemented for its type.
  • The automatically generated “drop glue” which recursively calls the destructors of the all fields of this value.

Rust会自动实现并调用drop,大部分情况下你不需要自己实现这个trait,而且你也不能手动调用Drop::drop(这是出于安全性考虑[2])。

手动实现Drop

但是,有些情况下确实是需要自己实现Drop,毕竟这并不是一个仅作标记的trait。
再次参照文档:

But there are some cases where it is useful, for example for types which directly manage a resource. That resource may be memory, it may be a file descriptor, it may be a network socket. Once a value of that type is no longer going to be used, it should “clean up” its resource by freeing the memory or closing the file or socket. This is the job of a destructor, and therefore the job of Drop::drop.

也就是说,当你需要类似“优雅关闭”的行为时,你就需要手动实现Drop来替换编译器生成的“drop glue”。需要注意的地方在于,你可能无法直接对被管理的资源本身实现Drop,因为这项资源的定义可能在别的地方,比如FFI调用的或是其他crate定义的,如果被管理的资源本身就无法进行正确的销毁,仅仅施放资源占用的内存可能无法达到想要的效果。

另一个情况则是,手动实现Drop来避免stackoverflow。
参考这个帖子,对于链表(帖子里用的是单链表)这种引用自身的结构,编译器进行的drop[4]是存在问题的。因为正如帖子里实验的(上文也提到过)那样,编译器生成的drop是递归进行的,这种潜在的栈结构在drop长链表时会出现stackoverflow,程序会直接panic掉[3]。

避免栈溢出的方法则很直白,实现循环式Drop而不是递归式Drop,比如对于帖子里提到的单链表:

  1. impl<Elem> Drop for List<Elem> {
  2. fn drop (self: &'_ mut List<Elem>)
  3. {
  4. // replace `self.head` with an empty Link to no-op the inherent drop glue
  5. // mem::take需要参数类型实现Default,你也可以使用mem::replace指定替换源。
  6. let mut this: Link<Elem> = mem::take(&mut self.head);
  7. while let Link::Cons(mut boxed_node) = this {
  8. this = mem::take(&mut boxed_node.next);
  9. // drop(boxed_node)
  10. }
  11. }
  12. }

这个实现相当于每次迭代都pop出一个节点进行drop,避免了递归。

鉴于单链表也是一种树,其他类似的数据结构也有相似的问题,需要手动实现Drop

对于Rc来说,The Book使用了Weak来预防环式引用

Note

  1. 其他情况可以参见Reference Book
  2. 但你可以使用std::mem::drop进行手动唤起drop行为,mem:drop可以获取参数的ownership,本质上就是额外建立了一层可被识别的scope,而Drop::drop的参数则只是&mut self
  3. 你可以在playground尝试这个。
  4. Box源码里指出它就是使用编译器生成的drop。