Skip to content

Commit 33324f5

Browse files
committed
rewrite Drop documentation
1 parent 97f3eee commit 33324f5

File tree

1 file changed

+98
-44
lines changed

1 file changed

+98
-44
lines changed

src/libcore/ops/drop.rs

+98-44
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,139 @@
1-
/// Used to run some code when a value goes out of scope.
2-
/// This is sometimes called a 'destructor'.
1+
/// Custom code within the destructor.
32
///
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.
78
///
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
1010
///
11-
/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book]
12-
/// for some more elaboration.
11+
/// This destructor consists of two components:
12+
/// - A call to `Drop::drop` for that value, if this special `Drop` trait is implemented for its type.
13+
/// - The automatically generated "drop glue" which recursively calls the destructors
14+
/// of the all fields of this value.
1315
///
14-
/// [book]: ../../book/ch15-03-drop.html
16+
/// As Rust automatically calls the destructors of all contained fields,
17+
/// you don't have to implement `Drop` in most cases. But there are some cases where
18+
/// it is useful, for example for types which directly manage a resource.
19+
/// That resource may be memory, it may be a file descriptor, it may be a network socket.
20+
/// Once a value of that type is no longer going to be used, it should "clean up" its
21+
/// resource by freeing the memory or closing the file or socket. This is
22+
/// the job of a destructor, and therefore the job of `Drop::drop`.
1523
///
16-
/// # Examples
24+
/// ## Examples
1725
///
18-
/// ## Implementing `Drop`
26+
/// To see destructors in action, let's take a look at the following program:
1927
///
20-
/// The `drop` method is called when `_x` goes out of scope, and therefore
21-
/// `main` prints `Dropping!`.
22-
///
23-
/// ```
28+
/// ```rust
2429
/// struct HasDrop;
2530
///
2631
/// impl Drop for HasDrop {
2732
/// fn drop(&mut self) {
28-
/// println!("Dropping!");
33+
/// println!("Dropping HasDrop!");
34+
/// }
35+
/// }
36+
///
37+
/// struct HasTwoDrops {
38+
/// one: HasDrop,
39+
/// two: HasDrop,
40+
/// }
41+
///
42+
/// impl Drop for HasTwoDrops {
43+
/// fn drop(&mut self) {
44+
/// println!("Dropping HasTwoDrops!");
2945
/// }
3046
/// }
3147
///
3248
/// fn main() {
33-
/// let _x = HasDrop;
49+
/// let _x = HasTwoDrops { one: HasDrop, two: HasDrop };
50+
/// println!("Running!");
3451
/// }
3552
/// ```
3653
///
37-
/// ## Dropping is done recursively
54+
/// Rust will first call `Drop::drop` for `_x` and then for both `_x.one` and `_x.two`,
55+
/// meaning that running this will print
3856
///
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!`.
57+
/// ```text
58+
/// Running!
59+
/// Dropping HasTwoDrops!
60+
/// Dropping HasDrop!
61+
/// Dropping HasDrop!
62+
/// ```
63+
///
64+
/// Even if we remove the implementation of `Drop` for `HasTwoDrop`, the destructors of its fields are still called.
65+
/// This would result in
4266
///
67+
/// ```test
68+
/// Running!
69+
/// Dropping HasDrop!
70+
/// Dropping HasDrop!
4371
/// ```
44-
/// struct Inner;
45-
/// struct Outer(Inner);
4672
///
47-
/// impl Drop for Inner {
73+
/// ## You cannot call `Drop::drop` yourself
74+
///
75+
/// Because `Drop::drop` is used to clean up a value, it may be dangerous to use this value after
76+
/// the method has been called. As `Drop::drop` does not take ownership of its input,
77+
/// Rust prevents misuse by not allowing you to call `Drop::drop` directly.
78+
///
79+
/// In other words, if you tried to explicitly call `Drop::drop` in the above example, you'd get a compiler error.
80+
///
81+
/// If you'd like explicitly call the destructor of a value, [`std::mem::drop`] can be used instead.
82+
///
83+
/// [`std::mem::drop`]: ../../std/mem/fn.drop.html
84+
///
85+
/// ## Drop order
86+
///
87+
/// Which of our two `HasDrop` drops first, though? For structs, it's the same
88+
/// order that they're declared: first `one`, then `two`. If you'd like to try
89+
/// this yourself, you can modify `HasDrop` above to contain some data, like an
90+
/// integer, and then use it in the `println!` inside of `Drop`. This behavior is
91+
/// guaranteed by the language.
92+
///
93+
/// Unlike for structs, local variables are dropped in reverse order:
94+
///
95+
/// ```rust
96+
/// struct Foo;
97+
///
98+
/// impl Drop for Foo {
4899
/// fn drop(&mut self) {
49-
/// println!("Dropping Inner!");
100+
/// println!("Dropping Foo!")
50101
/// }
51102
/// }
52103
///
53-
/// impl Drop for Outer {
104+
/// struct Bar;
105+
///
106+
/// impl Drop for Bar {
54107
/// fn drop(&mut self) {
55-
/// println!("Dropping Outer!");
108+
/// println!("Dropping Bar!")
56109
/// }
57110
/// }
58111
///
59112
/// fn main() {
60-
/// let _x = Outer(Inner);
113+
/// let _foo = Foo;
114+
/// let _bar = Bar;
61115
/// }
62116
/// ```
63117
///
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!`.
118+
/// This will print
68119
///
120+
/// ```text
121+
/// Dropping Bar!
122+
/// Dropping Foo!
69123
/// ```
70-
/// struct PrintOnDrop(&'static str);
71124
///
72-
/// impl Drop for PrintOnDrop {
73-
/// fn drop(&mut self) {
74-
/// println!("{}", self.0);
75-
/// }
76-
/// }
125+
/// Please see [the reference] for the full rules.
77126
///
78-
/// fn main() {
79-
/// let _first = PrintOnDrop("Declared first!");
80-
/// let _second = PrintOnDrop("Declared second!");
81-
/// }
82-
/// ```
127+
/// [the reference]: https://doc.rust-lang.org/reference/destructors.html
128+
///
129+
/// ## `Copy` and `Drop` are exclusive
130+
///
131+
/// You cannot implement both [`Copy`] and `Drop` on the same type. Types that
132+
/// are `Copy` get implicitly duplicated by the compiler, making it very
133+
/// hard to predict when, and how often destructors will be executed. As such,
134+
/// these types cannot have destructors.
135+
///
136+
/// [`Copy`]: ../../std/marker/trait.Copy.html
83137
#[lang = "drop"]
84138
#[stable(feature = "rust1", since = "1.0.0")]
85139
pub trait Drop {

0 commit comments

Comments
 (0)