使用Drop特性

对智能指针模式很重要的第二个特征是Drop,这样就可以 您可以自定义当值即将超出范围时发生的情况。您可以 为Droptrait 的 trait 中,那么该代码就可以 用于释放文件或网络连接等资源。

我们即将推出Drop在智能指针的上下文中,因为 的功能Droptrait 在实现 智能指针。例如,当Box<T>被丢弃时,它将释放 box 指向的堆上的空间。

在某些语言中,对于某些类型,程序员必须调用代码来释放内存 或 resources。例子 包括文件句柄、套接字或锁。如果他们忘记了,系统可能会 变得超负荷并崩溃。在 Rust 中,你可以指定特定的 每当值超出范围时运行代码,编译器将 此代码自动。因此,您无需小心 将清理代码放置在程序中任何位置的特定 type 已完成 - 您仍然不会泄漏资源!

您可以通过实现Drop特性。这Droptrait 要求您实现一个名为drop它接受对self.要查看 Rust 何时调用drop, 让我们实现dropprintln!声明。

示例 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 仍然会 自动调用dropmain.这将导致 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/)为准