feat: added cleanscript
This commit is contained in:
195
ch15/ch15-03-drop.html
Normal file
195
ch15/ch15-03-drop.html
Normal file
@@ -0,0 +1,195 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Running Code on Cleanup with the Drop Trait</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="running-code-on-cleanup-with-the-drop-trait"><a class="header" href="#running-code-on-cleanup-with-the-drop-trait">Running Code on Cleanup with the <code>Drop</code> Trait</a></h2>
|
||||
<p>The second trait important to the smart pointer pattern is <code>Drop</code>, which lets
|
||||
you customize what happens when a value is about to go out of scope. You can
|
||||
provide an implementation for the <code>Drop</code> trait on any type, and that code can
|
||||
be used to release resources like files or network connections.</p>
|
||||
<p>We’re introducing <code>Drop</code> in the context of smart pointers because the
|
||||
functionality of the <code>Drop</code> trait is almost always used when implementing a
|
||||
smart pointer. For example, when a <code>Box<T></code> is dropped, it will deallocate the
|
||||
space on the heap that the box points to.</p>
|
||||
<p>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!</p>
|
||||
<p>You specify the code to run when a value goes out of scope by implementing the
|
||||
<code>Drop</code> trait. The <code>Drop</code> trait requires you to implement one method named
|
||||
<code>drop</code> that takes a mutable reference to <code>self</code>. To see when Rust calls <code>drop</code>,
|
||||
let’s implement <code>drop</code> with <code>println!</code> statements for now.</p>
|
||||
<p>Listing 15-14 shows a <code>CustomSmartPointer</code> struct whose only custom
|
||||
functionality is that it will print <code>Dropping CustomSmartPointer!</code> when the
|
||||
instance goes out of scope, to show when Rust runs the <code>drop</code> method.</p>
|
||||
<figure class="listing" id="listing-15-14">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre class="playground"><code class="language-rust edition2024">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");
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-15-14">Listing 15-14</a>: A <code>CustomSmartPointer</code> struct that implements the <code>Drop</code> trait where we would put our cleanup code</figcaption>
|
||||
</figure>
|
||||
<p>The <code>Drop</code> trait is included in the prelude, so we don’t need to bring it into
|
||||
scope. We implement the <code>Drop</code> trait on <code>CustomSmartPointer</code> and provide an
|
||||
implementation for the <code>drop</code> method that calls <code>println!</code>. The body of the
|
||||
<code>drop</code> 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 <code>drop</code>.</p>
|
||||
<p>In <code>main</code>, we create two instances of <code>CustomSmartPointer</code> and then print
|
||||
<code>CustomSmartPointers created</code>. At the end of <code>main</code>, our instances of
|
||||
<code>CustomSmartPointer</code> will go out of scope, and Rust will call the code we put
|
||||
in the <code>drop</code> method, printing our final message. Note that we didn’t need to
|
||||
call the <code>drop</code> method explicitly.</p>
|
||||
<p>When we run this program, we’ll see the following output:</p>
|
||||
<pre><code class="language-console">$ 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`!
|
||||
</code></pre>
|
||||
<p>Rust automatically called <code>drop</code> 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 <code>d</code> was dropped before <code>c</code>. This example’s purpose is to
|
||||
give you a visual guide to how the <code>drop</code> method works; usually you would
|
||||
specify the cleanup code that your type needs to run rather than a print
|
||||
message.</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="dropping-a-value-early-with-std-mem-drop"></a></p>
|
||||
<p>Unfortunately, it’s not straightforward to disable the automatic <code>drop</code>
|
||||
functionality. Disabling <code>drop</code> isn’t usually necessary; the whole point of the
|
||||
<code>Drop</code> 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 <code>drop</code> method that
|
||||
releases the lock so that other code in the same scope can acquire the lock.
|
||||
Rust doesn’t let you call the <code>Drop</code> trait’s <code>drop</code> method manually; instead,
|
||||
you have to call the <code>std::mem::drop</code> function provided by the standard library
|
||||
if you want to force a value to be dropped before the end of its scope.</p>
|
||||
<p>Trying to call the <code>Drop</code> trait’s <code>drop</code> method manually by modifying the
|
||||
<code>main</code> function from Listing 15-14 won’t work, as shown in Listing 15-15.</p>
|
||||
<figure class="listing" id="listing-15-15">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore does_not_compile"><span class="boring">struct CustomSmartPointer {
|
||||
</span><span class="boring"> data: String,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Drop for CustomSmartPointer {
|
||||
</span><span class="boring"> fn drop(&mut self) {
|
||||
</span><span class="boring"> println!("Dropping CustomSmartPointer with data `{}`!", self.data);
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span>fn main() {
|
||||
let c = CustomSmartPointer {
|
||||
data: String::from("some data"),
|
||||
};
|
||||
println!("CustomSmartPointer created");
|
||||
c.drop();
|
||||
println!("CustomSmartPointer dropped before the end of main");
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-15-15">Listing 15-15</a>: Attempting to call the <code>drop</code> method from the <code>Drop</code> trait manually to clean up early</figcaption>
|
||||
</figure>
|
||||
<p>When we try to compile this code, we’ll get this error:</p>
|
||||
<pre><code class="language-console">$ 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 - c.drop();
|
||||
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
|
||||
</code></pre>
|
||||
<p>This error message states that we’re not allowed to explicitly call <code>drop</code>. The
|
||||
error message uses the term <em>destructor</em>, which is the general programming term
|
||||
for a function that cleans up an instance. A <em>destructor</em> is analogous to a
|
||||
<em>constructor</em>, which creates an instance. The <code>drop</code> function in Rust is one
|
||||
particular destructor.</p>
|
||||
<p>Rust doesn’t let us call <code>drop</code> explicitly, because Rust would still
|
||||
automatically call <code>drop</code> on the value at the end of <code>main</code>. This would cause a
|
||||
double free error because Rust would be trying to clean up the same value twice.</p>
|
||||
<p>We can’t disable the automatic insertion of <code>drop</code> when a value goes out of
|
||||
scope, and we can’t call the <code>drop</code> method explicitly. So, if we need to force
|
||||
a value to be cleaned up early, we use the <code>std::mem::drop</code> function.</p>
|
||||
<p>The <code>std::mem::drop</code> function is different from the <code>drop</code> method in the <code>Drop</code>
|
||||
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 <code>main</code> in Listing 15-15 to
|
||||
call the <code>drop</code> function, as shown in Listing 15-16.</p>
|
||||
<figure class="listing" id="listing-15-16">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre class="playground"><code class="language-rust edition2024"><span class="boring">struct CustomSmartPointer {
|
||||
</span><span class="boring"> data: String,
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span><span class="boring">impl Drop for CustomSmartPointer {
|
||||
</span><span class="boring"> fn drop(&mut self) {
|
||||
</span><span class="boring"> println!("Dropping CustomSmartPointer with data `{}`!", self.data);
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">}
|
||||
</span><span class="boring">
|
||||
</span>fn main() {
|
||||
let c = CustomSmartPointer {
|
||||
data: String::from("some data"),
|
||||
};
|
||||
println!("CustomSmartPointer created");
|
||||
drop(c);
|
||||
println!("CustomSmartPointer dropped before the end of main");
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-15-16">Listing 15-16</a>: Calling <code>std::mem::drop</code> to explicitly drop a value before it goes out of scope</figcaption>
|
||||
</figure>
|
||||
<p>Running this code will print the following:</p>
|
||||
<pre><code class="language-console">$ 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
|
||||
</code></pre>
|
||||
<p>The text <code>Dropping CustomSmartPointer with data `some data`!</code> is printed
|
||||
between the <code>CustomSmartPointer created</code> and <code>CustomSmartPointer dropped before the end of main</code> text, showing that the <code>drop</code> method code is called to drop
|
||||
<code>c</code> at that point.</p>
|
||||
<p>You can use code specified in a <code>Drop</code> 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 <code>Drop</code> trait and Rust’s ownership system, you
|
||||
don’t have to remember to clean up, because Rust does it automatically.</p>
|
||||
<p>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 <code>drop</code> gets called only once when
|
||||
the value is no longer being used.</p>
|
||||
<p>Now that we’ve examined <code>Box<T></code> and some of the characteristics of smart
|
||||
pointers, let’s look at a few other smart pointers defined in the standard
|
||||
library.</p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user