From c9d2f07a5ab50e4e7d9e61c03ddaf30d4baaf6a1 Mon Sep 17 00:00:00 2001 From: matthewjasper Date: Wed, 11 Oct 2017 21:46:11 +0100 Subject: [PATCH] Document destructors/drop. --- src/SUMMARY.md | 1 + src/destructors.md | 93 ++++++++++++++++++++++++++++++++ src/expressions/operator-expr.md | 17 +++--- src/glossory.md | 22 +++++--- 4 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 src/destructors.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c8dfe8630..dc9a3395b 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -66,6 +66,7 @@ - [Interior mutability](interior-mutability.md) - [Subtyping](subtyping.md) - [Type coercions](type-coercions.md) + - [Destructors](destructors.md) - [Special traits](special-traits.md) - [The Copy trait](the-copy-trait.md) diff --git a/src/destructors.md b/src/destructors.md new file mode 100644 index 000000000..c6fa1162b --- /dev/null +++ b/src/destructors.md @@ -0,0 +1,93 @@ +# Destructors + +When an [initialized] [variable] in Rust goes out of scope or a [temporary] +is no longer needed its _destructor_ is run. [Assignment] also runs the +destructor of its left-hand operand, unless it's an unitialized variable. If a +[struct] variable has been partially initialized, only its initialized fields +are dropped. + +The destrutor of a type consists of + +1. Calling its [`std::ops::Drop::drop`] method, if it has one. +2. Recursively running the destructor of all of its fields. + * The fields of a [struct], [tuple] or [enum variant] are dropped in + declaration order. \* + * The elements of an [array] or owned [slice][array] are dropped from the + first element to the last. \* + * The captured values of a [closure] are dropped in an unspecified order. + * [Trait objects] run the destructor of the underlying type. + * Other types don't result in any further drops. + +\* This order was stabilized in [RFC 1857]. + +Variables are dropped in reverse order of declaration. Variables declared in +the same pattern drop in an unspecified ordered. + +If a destructor must be run manually, such as when implementing your own smart +pointer, [`std::ptr::drop_in_place`] can be used. + +Some examples: + +```rust +struct ShowOnDrop(&'static str); + +impl Drop for ShowOnDrop { + fn drop(&mut self) { + println!("{}", self.0); + } +} + +{ + let mut overwritten = ShowOnDrop("Drops when overwritten"); + overwritten = ShowOnDrop("drops when scope ends"); +} +# println!(""); +{ + let declared_first = ShowOnDrop("Dropped last"); + let declared_last = ShowOnDrop("Dropped first"); +} +# println!(""); +{ + // Tuple elements drop in forwards order + let tuple = (ShowOnDrop("Tuple first"), ShowOnDrop("Tuple second")); +} +# println!(""); +loop { + // Tuple expression doesn't finish evaluating so temporaries drop in reverse order: + let partial_tuple = (ShowOnDrop("Temp first"), ShowOnDrop("Temp second"), break); +} +# println!(""); +{ + let moved; + // No destructor run on assignment. + moved = ShowOnDrop("Drops when moved"); + // drops now, but is then uninitialized + moved; + let uninitialized: ShowOnDrop; + // Only first element drops + let mut partially_initialized: (ShowOnDrop, ShowOnDrop); + partially_initialized.0 = ShowOnDrop("Partial tuple first"); +} +``` + +## Not running destructors + +Not running destructors in Rust is safe even if it has a type that isn't +`'static`. [`std::mem::ManuallyDrop`] provides a wrapper to prevent a +variable or field from being dropped automatically. + +[initialized]: glossary.html#initialized +[variable]: variables.html +[temporary]: expressions.html#temporary-lifetimes +[Assignment]: expressions/operator-expr.html#assignment-expressions +[`std::ops::Drop::drop`]: ../std/ops/trait.Drop.html +[RFC 1857]: https://github.com/rust-lang/rfcs/blob/master/text/1857-stabilize-drop-order.md +[struct]: types.html#struct +[tuple]: types.html#tuple-types +[enum variant]: types.html#enumeration-types +[array]: types.html#array-and-slice-types +[closure]: types.html#closure-types +[Trait objects]: types.html#trait-objects +[`std::ptr::drop_in_place`]: ../std/ptr/fn.drop_in_place.html +[`std::mem::forget`]: ../std/mem/fn.forget.html +[`std::mem::ManuallyDrop`]: ../std/mem/union.ManuallyDrop.html diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index c85d0438d..250feb989 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -301,14 +301,15 @@ same trait object. ## Assignment expressions An _assignment expression_ consists of an -[lvalue](expressions.html#lvalues-and-rvalues) expression followed -by an equals sign (`=`) and an -[rvalue](expressions.html#lvalues-and-rvalues) expression. - -Evaluating an assignment expression [either copies or -moves](expressions.html#moved-and-copied-types) its right-hand operand to its left-hand -operand. The left-hand operand must be an lvalue: using an rvalue results in a -compiler error, rather than promoting it to a temporary. +[lvalue](expressions.html#lvalues-and-rvalues) expression followed by an equals +sign (`=`) and an [rvalue](expressions.html#lvalues-and-rvalues) expression. + +Evaluating an assignment expression [drops](destructors.hmtl) the left-hand +operand, unless it's an unitialized local variable or field of a local variable, +and [either copies or moves](expressions.html#moved-and-copied-types) its +right-hand operand to its left-hand operand. The left-hand operand must be an +lvalue: using an rvalue results in a compiler error, rather than promoting it +to a temporary. ```rust # let mut x = 0; diff --git a/src/glossory.md b/src/glossory.md index 20a3a4456..44f308e88 100644 --- a/src/glossory.md +++ b/src/glossory.md @@ -25,7 +25,7 @@ must abide by that constraint. ### Combinator Combinators are higher-order functions that apply only functions and -earlier defined combinators to provide a result from its arguments. +earlier defined combinators to provide a result from its arguments. They can be used to manage control flow in a modular fashion. ### Dispatch @@ -37,15 +37,21 @@ through a mechanism called ‘trait objects’. ### Dynamically Sized Type -A dynamically sized type (DST) is a type without a statically known size or alignment. +A dynamically sized type (DST) is a type without a statically known size or alignment. ### Expression -An expression is a combination of values, constants, variables, operators +An expression is a combination of values, constants, variables, operators and functions that evaluate to a single value, with or without side-effects. For example, `2 + (3 * 4)` is an expression that returns the value 14. +### Initialized + +A variable is initialized if it has been assigned a value and hasn't since been +moved from. All other lvalues are assumed to be initialized. Only unsafe Rust +can create such an lvalue without initializing it. + ### Prelude Prelude, or The Rust Prelude, is a small collection of items - mostly traits - that are @@ -53,9 +59,9 @@ imported into very module of every crate. The traits in the prelude are pervasiv ### Slice -A slice is dynamically-sized view into a contiguous sequence, written as `[T]`. +A slice is dynamically-sized view into a contiguous sequence, written as `[T]`. -It is often seen in its borrowed forms, either mutable or shared. The shared +It is often seen in its borrowed forms, either mutable or shared. The shared slice type is `&[T]`, while the mutable slice type is `&mut [T]`, where `T` represents the element type. @@ -66,8 +72,8 @@ that commands a computer to perform an action. ### String literal -A string literal is a string stored directly in the final binary, and so will be -valid for the `'static` duration. +A string literal is a string stored directly in the final binary, and so will be +valid for the `'static` duration. Its type is `'static` duration borrowed string slice, `&'static str`. @@ -82,6 +88,6 @@ Strings slices are always valid UTF-8. ### Trait A trait is a language item that is used for describing the functionalities a type must provide. -It allow a type to make certain promises about its behavior. +It allow a type to make certain promises about its behavior. Generic functions and generic structs can exploit traits to constrain, or bound, the types they accept.