x-i18n: generated_at: “2026-03-01T14:33:44Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: b7be9004339b812131797124d5afc0658b35197e21de39d39ba7af814ad7488c source_path: ch15-03-drop.md workflow: 16
使用 Drop 特征在清理时运行代码 (Running Code on Cleanup with the Drop Trait)
Running Code on Cleanup with the Drop Trait
对智能指针模式很重要的第二个特征是 Drop ,它允许你自定义当一个值即将超出作用域时发生的事情。你可以在任何类型上提供 Drop 特征的实现,该代码可用于释放资源,如文件或网络连接。
The second trait important to the smart pointer pattern is Drop, which lets
you customize what happens when a value is about to go out of scope. You can
provide an implementation for the Drop trait on any type, and that code can
be used to release resources like files or network connections.
我们之所以在智能指针的上下文中介绍 Drop ,是因为在实现智能指针时几乎总是会用到 Drop 特征的功能。例如,当一个 Box<T> 被丢弃时,它会释放 Box 指向的堆空间。
We’re introducing Drop in the context of smart pointers because the
functionality of the Drop trait is almost always used when implementing a
smart pointer. For example, when a Box<T> is dropped, it will deallocate the
space on the heap that the box points to.
在某些语言中,对于某些类型,程序员每次使用完这些类型的实例后,必须调用代码来释放内存或资源。例子包括文件句柄、套接字 (sockets) 和锁 (locks)。如果程序员忘记了,系统可能会过载并崩溃。在 Rust 中,你可以指定每当一个值超出作用域时运行的一段特定代码,编译器将自动插入这段代码。因此,你不需要小心翼翼地在程序中使用完某个特定类型实例的每个地方放置清理代码——你仍然不会泄露资源!
In some languages, for some types, the programmer must call code to free memory or resources every time they finish using an instance of those types. Examples include file handles, sockets, and locks. If the programmer forgets, the system might become overloaded and crash. In Rust, you can specify that a particular bit of code be run whenever a value goes out of scope, and the compiler will insert this code automatically. As a result, you don’t need to be careful about placing cleanup code everywhere in a program that an instance of a particular type is finished with—you still won’t leak resources!
你通过实现 Drop 特征来指定值超出作用域时运行的代码。 Drop 特征要求你实现一个名为 drop 的方法,该方法接收一个对 self 的可变引用。为了看看 Rust 何时调用 drop ,我们目前先用 println! 语句来实现 drop 。
You specify the code to run when a value goes out of scope by implementing the
Drop trait. The Drop trait requires you to implement one method named
drop that takes a mutable reference to self. To see when Rust calls drop,
let’s implement drop with println! statements for now.
示例 15-14 展示了一个 CustomSmartPointer 结构体,其唯一的自定义功能是当实例超出作用域时打印 Dropping CustomSmartPointer! ,以此展示 Rust 何时运行 drop 方法。
Listing 15-14 shows a CustomSmartPointer struct whose only custom
functionality is that it will print Dropping CustomSmartPointer! when the
instance goes out of scope, to show when Rust runs the drop method.
#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-14/src/main.rs}}
}
Drop 特征包含在 prelude(预导入)中,所以我们不需要将其引入作用域。我们在 CustomSmartPointer 上实现 Drop 特征,并为调用 println! 的 drop 方法提供了一个实现。 drop 方法体是你放置当类型实例超出作用域时想要运行的任何逻辑的地方。我们在这里打印一些文本,以便直观地演示 Rust 何时调用 drop 。
The Drop trait is included in the prelude, so we don’t need to bring it into
scope. We implement the Drop trait on CustomSmartPointer and provide an
implementation for the drop method that calls println!. The body of the
drop method is where you would place any logic that you wanted to run when an
instance of your type goes out of scope. We’re printing some text here to
demonstrate visually when Rust will call drop.
在 main 中,我们创建了两个 CustomSmartPointer 实例,然后打印 CustomSmartPointers created 。在 main 结束时,我们的 CustomSmartPointer 实例将超出作用域,Rust 将调用我们在 drop 方法中放入的代码,打印我们的最后一条消息。注意我们不需要显式调用 drop 方法。
In main, we create two instances of CustomSmartPointer and then print
CustomSmartPointers created. At the end of main, our instances of
CustomSmartPointer will go out of scope, and Rust will call the code we put
in the drop method, printing our final message. Note that we didn’t need to
call the drop method explicitly.
当我们运行此程序时,我们将看到以下输出:
When we run this program, we’ll see the following output:
{{#include ../listings/ch15-smart-pointers/listing-15-14/output.txt}}
当我们的实例超出作用域时,Rust 自动为我们调用了 drop ,运行了我们指定的代码。变量按其创建的相反顺序被丢弃,因此 d 在 c 之前被丢弃。这个例子的目的是为你提供一个关于 drop 方法如何工作的直观指南;通常你会指定你的类型需要运行的清理代码,而不是一条打印消息。
Rust automatically called drop for us when our instances went out of scope,
calling the code we specified. Variables are dropped in the reverse order of
their creation, so d was dropped before c. This example’s purpose is to
give you a visual guide to how the drop method works; usually you would
specify the cleanup code that your type needs to run rather than a print
message.
不幸的是,禁用自动 drop 功能并不直接。通常不需要禁用 drop ; Drop 特征的全部意义就在于它是自动处理的。然而,有时你可能想提前清理一个值。一个例子是使用管理锁的智能指针:你可能想强制调用释放锁的 drop 方法,以便同一作用域内的其他代码可以获取锁。Rust 不允许你手动调用 Drop 特征的 drop 方法;相反,如果你想强制在值超出作用域之前将其丢弃,你必须调用标准库提供的 std::mem::drop 函数。
Unfortunately, it’s not straightforward to disable the automatic drop
functionality. Disabling drop isn’t usually necessary; the whole point of the
Drop trait is that it’s taken care of automatically. Occasionally, however,
you might want to clean up a value early. One example is when using smart
pointers that manage locks: You might want to force the drop method that
releases the lock so that other code in the same scope can acquire the lock.
Rust doesn’t let you call the Drop trait’s drop method manually; instead,
you have to call the std::mem::drop function provided by the standard library
if you want to force a value to be dropped before the end of its scope.
通过修改示例 15-14 中的 main 函数来尝试手动调用 Drop 特征的 drop 方法是行不通的,如示例 15-15 所示。
Trying to call the Drop trait’s drop method manually by modifying the
main function from Listing 15-14 won’t work, as shown in Listing 15-15.
{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-15/src/main.rs:here}}
当我们尝试编译这段代码时,我们会得到这个错误:
When we try to compile this code, we’ll get this error:
{{#include ../listings/ch15-smart-pointers/listing-15-15/output.txt}}
这条错误消息指出,我们不被允许显式调用 drop 。错误消息使用了术语“析构函数 (destructor)”,这是编程中对清理实例的函数的通用术语。“析构函数”类似于“构造函数 (constructor)”,后者创建实例。Rust 中的 drop 函数就是一个特定的析构函数。
This error message states that we’re not allowed to explicitly call drop. The
error message uses the term destructor, which is the general programming term
for a function that cleans up an instance. A destructor is analogous to a
constructor, which creates an instance. The drop function in Rust is one
particular destructor.
Rust 不允许我们显式调用 drop ,因为 Rust 仍然会在 main 结束时自动在该值上调用 drop 。这将导致双重释放错误,因为 Rust 将尝试两次清理同一个值。
Rust doesn’t let us call drop explicitly, because Rust would still
automatically call drop on the value at the end of main. This would cause a
double free error because Rust would be trying to clean up the same value twice.
我们无法禁用值超出作用域时 drop 的自动插入,我们也无法显式调用 drop 方法。因此,如果我们需要强制提前清理一个值,我们使用 std::mem::drop 函数。
We can’t disable the automatic insertion of drop when a value goes out of
scope, and we can’t call the drop method explicitly. So, if we need to force
a value to be cleaned up early, we use the std::mem::drop function.
std::mem::drop 函数与 Drop 特征中的 drop 方法不同。我们通过传入想要强制丢弃的值作为实参来调用它。该函数包含在 prelude 中,所以我们可以修改示例 15-15 中的 main 来调用该 drop 函数,如示例 15-16 所示。
The std::mem::drop function is different from the drop method in the Drop
trait. We call it by passing as an argument the value we want to force-drop.
The function is in the prelude, so we can modify main in Listing 15-15 to
call the drop function, as shown in Listing 15-16.
#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-16/src/main.rs:here}}
}
运行这段代码将打印以下内容:
Running this code will print the following:
{{#include ../listings/ch15-smart-pointers/listing-15-16/output.txt}}
文本 Dropping CustomSmartPointer with data `some data`! 被打印在 CustomSmartPointer created 和 CustomSmartPointer dropped before the end of main 文本之间,表明 drop 方法代码在此时被调用来丢弃 c 。
The text Dropping CustomSmartPointer with data `some data`! is printed
between the CustomSmartPointer created and CustomSmartPointer dropped before the end of main text, showing that the drop method code is called to drop
c at that point.
你可以通过多种方式使用 Drop 特征实现中指定的代码,使清理变得方便且安全:例如,你可以用它来创建你自己的内存分配器!有了 Drop 特征和 Rust 的所有权系统,你不需要记得去清理,因为 Rust 会自动完成。
You can use code specified in a Drop trait implementation in many ways to
make cleanup convenient and safe: For instance, you could use it to create your
own memory allocator! With the Drop trait and Rust’s ownership system, you
don’t have to remember to clean up, because Rust does it automatically.
你也不必担心由于意外清理仍在使用中的值而产生的问题:确保引用始终有效的所有权系统还确保了当值不再被使用时 drop 仅被调用一次。
You also don’t have to worry about problems resulting from accidentally
cleaning up values still in use: The ownership system that makes sure
references are always valid also ensures that drop gets called only once when
the value is no longer being used.
现在我们已经研究了 Box<T> 和智能指针的一些特性,让我们看看标准库中定义的其他一些智能指针。
Now that we’ve examined Box<T> and some of the characteristics of smart
pointers, let’s look at a few other smart pointers defined in the standard
library.