1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/// 析构函数中的自定义代码。
///
/// 当不再需要某个值时,Rust 将对该值运行 "析构函数"。
/// 不再需要值的最常见方法是离开作用域。析构函数可能仍在其他情况下运行,但是在这里的示例中,我们将重点关注作用域。
/// 要了解其他一些情况,请参见析构函数的 [参考][the reference] 部分。
///
/// [the reference]: https://doc.rust-lang.org/reference/destructors.html
///
/// 此析构函数由两个组件组成:
/// - 如果为此类型实现了特殊的 `Drop` trait,则对该值调用 `Drop::drop`。
/// - 自动生成的 "drop glue" 递归调用该值的所有字段的析构函数。
///
/// 由于 Rust 自动调用所有包含字段的析构函数,因此在大多数情况下,您无需实现 `Drop`。但是在某些情况下它很有用,例如对于直接管理资源的类型。
/// 该资源可能是内存,可能是文件描述符,可能是网络套接字。
/// 一旦不再使用该类型的值,则应通过释放内存或关闭文件或套接字 "clean up" 资源。这是析构函数的工作,因此也是 `Drop::drop` 的工作。
///
/// ## Examples
///
/// 要查看析构函数的作用,让我们看一下以下程序:
///
/// ```rust
/// struct HasDrop;
///
/// impl Drop for HasDrop {
///     fn drop(&mut self) {
///         println!("Dropping HasDrop!");
///     }
/// }
///
/// struct HasTwoDrops {
///     one: HasDrop,
///     two: HasDrop,
/// }
///
/// impl Drop for HasTwoDrops {
///     fn drop(&mut self) {
///         println!("Dropping HasTwoDrops!");
///     }
/// }
///
/// fn main() {
///     let _x = HasTwoDrops { one: HasDrop, two: HasDrop };
///     println!("Running!");
/// }
/// ```
///
/// Rust 将首先为 `_x` 调用 `Drop::drop`,然后为 `_x.one` 和 `_x.two` 调用,这意味着运行此命令将打印
///
/// ```text
/// Running!
/// Dropping HasTwoDrops!
/// Dropping HasDrop!
/// Dropping HasDrop!
/// ```
///
/// 即使我们删除了针对 `HasTwoDrop` 的 `Drop` 的实现,其字段的析构函数仍然会被调用。
/// 这将导致
///
/// ```test
/// Running!
/// Dropping HasDrop!
/// Dropping HasDrop!
/// ```
///
/// ## 您不能自己调用 `Drop::drop`
///
/// 因为 `Drop::drop` 是用来清理一个值的,所以在调用方法后使用该值可能很危险。
/// 由于 `Drop::drop` 不拥有其输入的所有权,因此 Rust 通过不允许您直接调用 `Drop::drop` 来防止误用。
///
/// 换句话说,如果您在上面的示例中尝试显式调用 `Drop::drop`,则会出现编译器错误。
///
/// 如果您想显式调用一个值的析构函数,可以使用 [`mem::drop`] 代替。
///
/// [`mem::drop`]: drop
///
/// ## Drop 指令
///
/// 但是,我们的两个 `HasDrop` 哪个先丢弃掉? 对于结构体,其声明顺序相同:首先是 `one`,然后是 `two`。
/// 如果您想自己尝试一下,可以修改上面的 `HasDrop` 以包含一些数据 (例如整数),然后在 `Drop` 内部的 `println!` 中使用它。
/// 此行为由语言保证。
///
/// 与结构体不同,局部变量以相反的顺序丢弃:
///
/// ```rust
/// struct Foo;
///
/// impl Drop for Foo {
///     fn drop(&mut self) {
///         println!("Dropping Foo!")
///     }
/// }
///
/// struct Bar;
///
/// impl Drop for Bar {
///     fn drop(&mut self) {
///         println!("Dropping Bar!")
///     }
/// }
///
/// fn main() {
///     let _foo = Foo;
///     let _bar = Bar;
/// }
/// ```
///
/// 这将打印
///
/// ```text
/// Dropping Bar!
/// Dropping Foo!
/// ```
///
/// 有关完整规则,请参见 [the reference]。
///
/// [the reference]: https://doc.rust-lang.org/reference/destructors.html
///
/// ## `Copy` 和 `Drop` 是排他的
///
/// 您不能在同一类型上同时实现 [`Copy`] 和 `Drop`。`Copy` 类型被编译器隐式复制,这使得很难预测何时以及将执行析构函数的频率。
/// 因此,这些类型不能有析构函数。
///
/// ## 丢弃检查
///
/// 丢弃以微妙的方式与借用检查器交互: 当类型 `T` 被隐式丢弃为这种类型的某个变量时离开作用域,借用检查器需要确保此时调用 `T` 的析构函数是安全的。
///
/// 特别是,还需要安全地递归丢弃 `T` 的所有字段。
/// 例如,拒绝像下面这样的代码是至关重要的:
///
/// ```compile_fail,E0597
/// use std::cell::Cell;
///
/// struct S<'a>(Cell<Option<&'a S<'a>>>, Box<i32>);
/// impl Drop for S<'_> {
///     fn drop(&mut self) {
///         if let Some(r) = self.0.get() {
///             // 在 `r` 中打印 `Box` 的内容。
///             println!("{}", r.1);
///         }
///     }
/// }
///
/// fn main() {
///     // 设置两个相互指向的 `S`。
///     let s1 = S(Cell::new(None), Box::new(42));
///     let s2 = S(Cell::new(Some(&s1)), Box::new(42));
///     s1.0.set(Some(&s2));
///     // 现在他们都丢弃了。
///     // 但是第 2 个丢掉的那个会在第一个中访问 `Box`,这是一个 use-after-free!
/////
/// }
/// ```
///
/// Nomicon 讨论了对 [drop check in more detail][drop check] 的需求。
///
/// 为了拒绝这样的代码,"drop check" 分析确定当 `T` 得到弃弃时哪些类型和生命周期需要仍然存在。此分析的确切细节尚未得到稳定保证,并且**可能会发生变化**。
/// 目前,分析工作如下:
/// - 如果 `T` 没有抛弃胶水,那么什么都不需要活着。如果 `T` 及其任何 (recursive) 字段都没有析构函数 (`impl Drop`),就会出现这种情况。
/// [`PhantomData`] 和 [`ManuallyDrop`] 被认为永远没有析构函数,无论它们的字段类型如何。
/// - 如果 `T` 有丢弃胶水,那么,对于 `T` 的任何字段*拥有*的所有类型 `U`,递归添加 `U` 获得丢弃时需要存活的类型和生命周期。拥有类型的集合是通过递归遍历 `T` 来确定的:
///   - 通过 `PhantomData`、`Box`、元组和数组 (包括长度为 0 的数组) 递归下降。
///   - 停在引用和裸指针类型以及函数指针和函数项上;
///     他们不拥有任何东西。
///   - 停在非复合类型 (当前上下文中保留泛型的类型参数和整数、`bool` 等基类型) ; 这些类型是拥有所有权的。
///   - 当用 `impl Drop` 击中 ADT 时,停在那里; 这种类型是拥有所有权的。
///   - 在没有 `impl Drop` 的情况下命中 ADT 时,递归下降到它的字段。
/// (对于 `enum`,考虑所有变体的所有字段。)
/// - 此外,如果 `T` 实现 `Drop`,则 `T` 的所有泛型 (生命周期和类型) 参数都必须有效。
///
/// 在上面的例子中,最后一个子句暗示当 `S<'a>` 是丢弃时 `'a` 必须是 live,因此该例子被拒绝。如果我们删除 `impl Drop`,则活性要求消失并且该示例被接受。
///
/// 存在一种类型选择退出最后一个子句的不稳定方式; 这称为 "drop check eyepatch" 或 `may_dangle`。有关此仅限夜间,的更多详细信息,请参见 [discussion in the Nomicon][nomicon]。
///
/// [`ManuallyDrop`]: crate::mem::ManuallyDrop
/// [`PhantomData`]: crate::marker::PhantomData
/// [drop check]: ../../nomicon/dropck.html
/// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
#[const_trait]
pub trait Drop {
    /// 执行此类型的析构函数。
    ///
    /// 当值离开作用域时隐式调用此方法,并且不能显式调用此方法 (会得到编译器 [E0040] 错误)。
    /// 但是,prelude 中的 [`mem::drop`] 函数可用于调用参数的 `Drop` 实现。
    ///
    /// 当这个方法被调用时,`self` 还没有被释放。
    /// 只有在方法结束后才会发生这种情况。
    /// 如果不是这种情况,那么 `self` 将是悬垂引用。
    ///
    /// # Panics
    ///
    /// 考虑到 [`panic!`] 将在展开时调用 `drop`,因此 `drop` 实现中的任何 [`panic!`] 都可能会中止。
    ///
    /// 请注意,即使此 panics,该值也被视为已丢弃;
    /// 您不得再次调用 `drop`。
    /// 这通常由编译器自动处理,但是在使用不安全的代码时,有时可能会无意间发生,尤其是在使用 [`ptr::drop_in_place`] 时。
    ///
    ///
    /// [E0040]: ../../error_codes/E0040.html
    /// [`panic!`]: crate::panic!
    /// [`mem::drop`]: drop
    /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place
    ///
    ///
    ///
    #[stable(feature = "rust1", since = "1.0.0")]
    fn drop(&mut self);
}