使用Drop特性
对智能指针模式很重要的第二个特征是Drop,这样就可以
您可以自定义当值即将超出范围时发生的情况。您可以
为Droptrait 的 trait 中,那么该代码就可以
用于释放文件或网络连接等资源。
我们即将推出Drop在智能指针的上下文中,因为
的功能Droptrait 在实现
智能指针。例如,当Box<T>被丢弃时,它将释放
box 指向的堆上的空间。
在某些语言中,对于某些类型,程序员必须调用代码来释放内存 或 resources。例子 包括文件句柄、套接字或锁。如果他们忘记了,系统可能会 变得超负荷并崩溃。在 Rust 中,你可以指定特定的 每当值超出范围时运行代码,编译器将 此代码自动。因此,您无需小心 将清理代码放置在程序中任何位置的特定 type 已完成 - 您仍然不会泄漏资源!
您可以通过实现Drop特性。这Droptrait 要求您实现一个名为drop它接受对self.要查看 Rust 何时调用drop,
让我们实现drop跟println!声明。
示例 15-14 显示了一个CustomSmartPointerstruct 中唯一自定义的
功能是它将打印Dropping CustomSmartPointer!当
实例超出范围,以显示 Rust 何时运行drop功能。
文件名: src/main.rs
struct CustomSmartPointer { data: String, } impl Drop for CustomSmartPointer { fn drop(&mut self) { println!("Dropping CustomSmartPointer with data `{}`!", self.data); } } fn main() { let c = CustomSmartPointer { data: String::from("my stuff"), }; let d = CustomSmartPointer { data: String::from("other stuff"), }; println!("CustomSmartPointers created."); }
示例 15-14:一个CustomSmartPointerstruct 的
实现Droptrait 中放置清理代码的位置
这Droptrait 包含在 Prelude 中,因此我们不需要将其引入
范围。我们实现Droptrait 开启CustomSmartPointer并提供
实现drop调用println!.主体dropfunction 是放置任何要运行的 logic 的位置
类型的实例超出范围。我们在此处打印一些文本以
直观地演示 Rust 何时调用drop.
在main中,我们创建两个CustomSmartPointer,然后打印CustomSmartPointers created.在main、我们的CustomSmartPointer将超出范围,Rust 将调用我们放置
在drop方法,打印我们的最终消息。请注意,我们不需要
调用drop方法。
当我们运行这个程序时,我们将看到以下输出:
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.60s
Running `target/debug/drop-example`
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
Rust 自动调用drop对我们来说,当我们的实例超出范围时,
调用我们指定的代码。变量的删除顺序与
他们的创造,所以d之前被丢弃c.此示例的目的是
为您提供一个直观的指南,让您了解如何drop方法有效;通常你会
指定您的类型需要运行的清理代码,而不是 print
消息。
提前删除值std::mem::drop
不幸的是,禁用自动drop功能性。禁用drop通常不是必需的;的重点Droptrait 是它会自动处理。然而,偶尔,
您可能希望尽早清理值。一个例子是使用 smart
管理锁的指针:您可能希望强制drop方法,该
释放锁,以便同一范围内的其他代码可以获取锁。
Rust 不允许你调用Droptrait 的drop方法;相反
您必须调用std::mem::drop标准库提供的函数
如果要强制在其范围结束之前删除值。
如果我们尝试调用Droptrait 的drop方法,方法是修改main函数,如示例 15-15 所示,我们将得到一个
编译器错误:
文件名: src/main.rs
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
c.drop();
println!("CustomSmartPointer dropped before the end of main.");
}
示例 15-15:尝试调用dropmethod 从
这Droptrait 来尽早清理
当我们尝试编译此代码时,我们将收到此错误:
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
error[E0040]: explicit use of destructor method
--> src/main.rs:16:7
|
16 | c.drop();
| ^^^^ explicit destructor calls not allowed
|
help: consider using `drop` function
|
16 | drop(c);
| +++++ ~
For more information about this error, try `rustc --explain E0040`.
error: could not compile `drop-example` (bin "drop-example") due to 1 previous error
此错误消息指出,不允许我们显式调用drop.这
错误消息使用术语 Destructor,这是通用的编程术语
对于清理实例的函数。析构函数类似于创建实例的构造函数。这dropfunction 是一个
特定的析构函数。
Rust 不允许我们调用drop因为 Rust 仍然会
自动调用drop在main.这将导致 double free 错误,因为 Rust 会尝试清理相同的值
两次。
我们不能禁用drop当值超出
范围,我们不能调用drop方法。所以,如果我们需要强制
一个值,我们使用std::mem::drop功能。
这std::mem::drop函数与drop方法中的Drop特性。我们通过将要强制 drop 的值作为参数传递来调用它。
函数在 prelude 中,因此我们可以修改main在示例 15-15 中为
调用drop函数,如示例 15-16 所示:
文件名: src/main.rs
struct CustomSmartPointer { data: String, } impl Drop for CustomSmartPointer { fn drop(&mut self) { println!("Dropping CustomSmartPointer with data `{}`!", self.data); } } fn main() { let c = CustomSmartPointer { data: String::from("some data"), }; println!("CustomSmartPointer created."); drop(c); println!("CustomSmartPointer dropped before the end of main."); }
示例 15-16:调用std::mem::drop显式
在值超出范围之前删除值
运行此代码将打印以下内容:
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.73s
Running `target/debug/drop-example`
CustomSmartPointer created.
Dropping CustomSmartPointer with data `some data`!
CustomSmartPointer dropped before the end of main.
文本Dropping CustomSmartPointer with data `some data`!已打印
在CustomSmartPointer created.和CustomSmartPointer dropped before the end of main.文本,显示drop方法代码被调用到
落c在那个时候。
您可以使用在Droptrait 实现以多种方式实现
使清理方便和安全:例如,您可以使用它来创建您的
自己的内存分配器!使用Droptrait 和 Rust 的所有权系统,你
不必记得清理,因为 Rust 会自动进行清理。
您也不必担心因意外而导致的问题
清理仍在使用的值:确保 OWNERSHIP SYSTEM
references are always valid 还确保drop在以下情况下仅调用一次
该值不再被使用。
现在我们已经检查了Box<T>以及 smart 的一些特性
pointers,让我们看看标准
图书馆。
本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准