|
1 |
| -/// Used to run some code when a value goes out of scope. |
2 |
| -/// This is sometimes called a 'destructor'. |
| 1 | +/// Destructors for cleaning up resources |
3 | 2 | ///
|
4 |
| -/// When a value goes out of scope, it will have its `drop` method called if |
5 |
| -/// its type implements `Drop`. Then, any fields the value contains will also |
6 |
| -/// be dropped recursively. |
| 3 | +/// When a value is no longer needed, Rust will run a "destructor" on that value. |
| 4 | +/// The most common way that a value is no longer needed is when it goes out of |
| 5 | +/// scope. Destructors may still run in other circumstances, but we're going to |
| 6 | +/// focus on scope for the examples here. To learn about some of those other cases, |
| 7 | +/// please see [the reference] section on destructors. |
7 | 8 | ///
|
8 |
| -/// Because of this recursive dropping, you do not need to implement this trait |
9 |
| -/// unless your type needs its own destructor logic. |
| 9 | +/// [the reference]: https://doc.rust-lang.org/reference/destructors.html |
10 | 10 | ///
|
11 |
| -/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book] |
12 |
| -/// for some more elaboration. |
13 |
| -/// |
14 |
| -/// [book]: ../../book/ch15-03-drop.html |
15 |
| -/// |
16 |
| -/// # Examples |
| 11 | +/// The `Drop` trait provides a way to implement a custom destructor on a type. |
| 12 | +/// Why would you want such a thing? Well, many types aren't only data: they |
| 13 | +/// manage some sort of resource. That resource may be memory, it may be a file |
| 14 | +/// descriptor, it may be a network socket. But when the type is no longer going |
| 15 | +/// to be used, it should "clean up" that resource by freeing the memory or |
| 16 | +/// closing the file or socket. This is the job of a destructor, and therefore |
| 17 | +/// the job for `Drop::drop`. |
17 | 18 | ///
|
18 | 19 | /// ## Implementing `Drop`
|
19 | 20 | ///
|
20 |
| -/// The `drop` method is called when `_x` goes out of scope, and therefore |
21 |
| -/// `main` prints `Dropping!`. |
| 21 | +/// When a value goes out of scope, it will call `Drop::drop` on that value. For example, |
22 | 22 | ///
|
23 |
| -/// ``` |
| 23 | +/// ```rust |
24 | 24 | /// struct HasDrop;
|
25 | 25 | ///
|
26 | 26 | /// impl Drop for HasDrop {
|
|
34 | 34 | /// }
|
35 | 35 | /// ```
|
36 | 36 | ///
|
37 |
| -/// ## Dropping is done recursively |
| 37 | +/// Here, `main` will print `Dropping!`. In other words, the compiler generates code that |
| 38 | +/// kind of looks like this: |
| 39 | +/// |
| 40 | +/// ```rust,compile_fail,E0040 |
| 41 | +/// # struct HasDrop; |
38 | 42 | ///
|
39 |
| -/// When `outer` goes out of scope, the `drop` method will be called first for |
40 |
| -/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and |
41 |
| -/// then `Dropping Inner!`. |
| 43 | +/// # impl Drop for HasDrop { |
| 44 | +/// # fn drop(&mut self) { |
| 45 | +/// # println!("Dropping!"); |
| 46 | +/// # } |
| 47 | +/// # } |
| 48 | +/// fn main() { |
| 49 | +/// let _x = HasDrop; |
42 | 50 | ///
|
| 51 | +/// let mut x = _x; |
| 52 | +/// Drop::drop(&mut x); |
| 53 | +/// } |
43 | 54 | /// ```
|
44 |
| -/// struct Inner; |
45 |
| -/// struct Outer(Inner); |
46 | 55 | ///
|
47 |
| -/// impl Drop for Inner { |
| 56 | +/// As you can see, our custom implementation of `Drop` will be called at the end of `main`. |
| 57 | +/// |
| 58 | +/// ## You cannot call `Drop::drop` yourself |
| 59 | +/// |
| 60 | +/// Because the compiler automatically calls `Drop::drop`, you cannot call it yourself. This |
| 61 | +/// would lead to "double drop", where `Drop::drop` is called twice on the same value. This |
| 62 | +/// can lead to things like "double frees". |
| 63 | +/// |
| 64 | +/// In other words, if you tried to write the code in the previous example with the explicit |
| 65 | +/// call to `Drop::drop`, you'd get a compiler error. |
| 66 | +/// |
| 67 | +/// If you'd like to call `drop` yourself, there is something you can do: call [`std::mem::drop`]. |
| 68 | +/// This function will drop its argument. For more, see its documentation. |
| 69 | +/// |
| 70 | +/// [`std::mem::drop`]: ../../std/mem/fn.drop.html |
| 71 | +/// |
| 72 | +/// ## `Drop` is recursive |
| 73 | +/// |
| 74 | +/// If your type is something like a `struct` or `enum` that is an aggregate of other types, then |
| 75 | +/// Rust will call `Drop::drop` on the type first, and then recursively on everything it contains. |
| 76 | +/// For example: |
| 77 | +/// |
| 78 | +/// ```rust |
| 79 | +/// struct HasDrop; |
| 80 | +/// |
| 81 | +/// impl Drop for HasDrop { |
48 | 82 | /// fn drop(&mut self) {
|
49 |
| -/// println!("Dropping Inner!"); |
| 83 | +/// println!("Dropping HasDrop!"); |
50 | 84 | /// }
|
51 | 85 | /// }
|
52 | 86 | ///
|
53 |
| -/// impl Drop for Outer { |
| 87 | +/// struct HasTwoDrops { |
| 88 | +/// one: HasDrop, |
| 89 | +/// two: HasDrop, |
| 90 | +/// } |
| 91 | +/// |
| 92 | +/// impl Drop for HasTwoDrops { |
54 | 93 | /// fn drop(&mut self) {
|
55 |
| -/// println!("Dropping Outer!"); |
| 94 | +/// println!("Dropping HasTwoDrops!"); |
56 | 95 | /// }
|
57 | 96 | /// }
|
58 | 97 | ///
|
59 | 98 | /// fn main() {
|
60 |
| -/// let _x = Outer(Inner); |
| 99 | +/// let _x = HasTwoDrops { one: HasDrop, two: HasDrop }; |
61 | 100 | /// }
|
62 | 101 | /// ```
|
63 | 102 | ///
|
64 |
| -/// ## Variables are dropped in reverse order of declaration |
65 |
| -/// |
66 |
| -/// `_first` is declared first and `_second` is declared second, so `main` will |
67 |
| -/// print `Declared second!` and then `Declared first!`. |
| 103 | +/// This will print |
68 | 104 | ///
|
| 105 | +/// ```text |
| 106 | +/// Dropping HasTwoDrops! |
| 107 | +/// Dropping HasDrop! |
| 108 | +/// Dropping HasDrop! |
69 | 109 | /// ```
|
70 |
| -/// struct PrintOnDrop(&'static str); |
71 | 110 | ///
|
72 |
| -/// impl Drop for PrintOnDrop { |
73 |
| -/// fn drop(&mut self) { |
74 |
| -/// println!("{}", self.0); |
75 |
| -/// } |
76 |
| -/// } |
| 111 | +/// Similarly, a slice will drop each element in order. |
77 | 112 | ///
|
78 |
| -/// fn main() { |
79 |
| -/// let _first = PrintOnDrop("Declared first!"); |
80 |
| -/// let _second = PrintOnDrop("Declared second!"); |
81 |
| -/// } |
82 |
| -/// ``` |
| 113 | +/// Which of our two `HasDrop` drops first, though? It's the same order that |
| 114 | +/// they're declared: first `one`, then `two`. If you'd like to try this |
| 115 | +/// yourself, you can modify `HasDrop` above to contain some data, like an |
| 116 | +/// integer, and then use it in the `println!` inside of `Drop`. This behavior |
| 117 | +/// is guaranteed by the language. |
| 118 | +/// |
| 119 | +/// ## `Copy` and `Drop` are exclusive |
| 120 | +/// |
| 121 | +/// You cannot implement both [`Copy`] and `Drop` on the same type. Types that |
| 122 | +/// are `Copy` don't manage resources, and can be freely copied. As such, they |
| 123 | +/// cannot have destructors. |
| 124 | +/// |
| 125 | +/// [`Copy`]: ../../std/marker/trait.Copy.html |
83 | 126 | #[lang = "drop"]
|
84 | 127 | #[stable(feature = "rust1", since = "1.0.0")]
|
85 | 128 | pub trait Drop {
|
|
0 commit comments