Trait std::ops::Drop 1.0.0[−][src]
pub trait Drop {
fn drop(&mut self);
}
Expand description
析构函数中的自定义代码。
当不再需要某个值时,Rust 将对该值运行 “析构函数”。 不再需要值的最常见方法是离开作用域。析构函数可能仍在其他情况下运行,但是在这里的示例中,我们将重点关注作用域。 要了解其他一些情况,请参见析构函数的 参考 部分。
此析构函数由两个组件组成:
- 如果为此类型实现了特殊的
Drop
trait,则对该值调用Drop::drop
。 - 自动生成的 “drop glue” 递归调用该值的所有字段的析构函数。
由于 Rust 自动调用所有包含字段的析构函数,因此在大多数情况下,您无需实现 Drop
。
但是在某些情况下它很有用,例如对于直接管理资源的类型。
该资源可能是内存,可能是文件描述符,可能是网络套接字。
一旦不再使用该类型的值,则应通过释放内存或关闭文件或套接字 “clean up” 资源。
这是析构函数的工作,因此也是 Drop::drop
的工作。
Examples
要查看析构函数的作用,让我们看一下以下程序:
struct HasDrop;
impl Drop for HasDrop {
fn drop(&mut self) {
println!("Dropping HasDrop!");
}
}
struct HasTwoDrops {
one: HasDrop,
two: HasDrop,
}
impl Drop for HasTwoDrops {
fn drop(&mut self) {
println!("Dropping HasTwoDrops!");
}
}
fn main() {
let _x = HasTwoDrops { one: HasDrop, two: HasDrop };
println!("Running!");
}
RunRust 将首先为 _x
调用 Drop::drop
,然后为 _x.one
和 _x.two
调用,这意味着运行此命令将打印
Running!
Dropping HasTwoDrops!
Dropping HasDrop!
Dropping HasDrop!
即使我们删除了针对 HasTwoDrop
的 Drop
的实现,其字段的析构函数仍然会被调用。
这将导致
Running!
Dropping HasDrop!
Dropping HasDrop!
您不能自己调用 Drop::drop
因为 Drop::drop
是用来清理一个值的,所以在调用方法后使用该值可能很危险。
由于 Drop::drop
不拥有其输入的所有权,因此 Rust 通过不允许您直接调用 Drop::drop
来防止误用。
换句话说,如果您在上面的示例中尝试显式调用 Drop::drop
,则会出现编译器错误。
如果您想显式调用一个值的析构函数,可以使用 mem::drop
代替。
Drop 指令
但是,我们的两个 HasDrop
哪个先丢弃掉? 对于结构体,其声明顺序相同:首先是 one
,然后是 two
。
如果您想自己尝试一下,可以修改上面的 HasDrop
以包含一些数据 (例如整数),然后在 Drop
内部的 println!
中使用它。
此行为由语言保证。
与结构体不同,局部变量以相反的顺序丢弃:
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
println!("Dropping Foo!")
}
}
struct Bar;
impl Drop for Bar {
fn drop(&mut self) {
println!("Dropping Bar!")
}
}
fn main() {
let _foo = Foo;
let _bar = Bar;
}
Run这将打印
Dropping Bar!
Dropping Foo!
有关完整规则,请参见 the reference。
Copy
和 Drop
是排他的
您不能在同一类型上同时实现 Copy
和 Drop
。Copy
类型被编译器隐式复制,这使得很难预测何时以及将执行析构函数的频率。
因此,这些类型不能有析构函数。
Required methods
执行此类型的析构函数。
当值离开作用域时隐式调用此方法,并且不能显式调用此方法 (会得到编译器 E0040 错误)。
但是,prelude 中的 mem::drop
函数可用于调用参数的 Drop
实现。
当这个方法被调用时,self
还没有被释放。
只有在方法结束后才会发生这种情况。
如果不是这种情况,那么 self
将是悬垂引用。
Panics
考虑到 panic!
在展开时将调用 drop
,因此 drop
实现中的任何 panic!
都可能会终止。
请注意,即使此 panics,该值也被视为已丢弃;
您不得再次调用 drop
。
这通常由编译器自动处理,但是在使用不安全的代码时,有时可能会无意间发生,尤其是在使用 ptr::drop_in_place
时。