I was hoping that if I wrap a Box<T>
into an Option
, drop just does its thing. And this program indeed outputs "dropped":
trait Foo {}
struct Bar {}
impl Foo for Bar {}
impl Drop for Bar {
fn drop(&mut self) {
println!("dropped")
}
}
fn main() {
let x = Box::new( Bar {} ) as Box<Foo>;
let _y = Option::Some(x);
}
I checked the documentation of both Option
and Drop
and I could not find a description of this behavior. Did I miss some compiler magic, or am I right that it cannot be implemented elsewhere, just in the trait declaration or implementor definition?
How does Option
implement Drop
and why is it missing from the documentation?
The docs don't mention Option<T>
implementing Drop
because it doesn't implement it.
The Drop
trait is only needed when you want your struct or enum to have some special behaviour. If the only thing you need is to free the memory and run child elements' destructors, the compiler will do so on its own. From the relevant page in the Rustonomicon:
If a struct has no special logic for being dropped other than dropping its children, then it means
Drop
doesn't need to be implemented at all!
Option
has no Drop
implementation because there's no special logic involved in its destruction, unlike with Rc
(which decrements the reference counter), or with a MutexGuard
(which unlocks the parent mutex). You can observe the same behaviour with your own types, Bar
s in a struct Thingie(Bar, Bar)
will be dropped the same as if wrapped in Some
.
Note that everywhere above "X has no Drop
implementation" really means no implementation - the compiler will not make one implicitly.
You can also directly test if a type implements Drop
or not:
fn test_for_drop<T: Drop>() { }
fn main() {
test_for_drop::<Option<i32>>();
}
This produces an error:
error[E0277]: the trait bound `std::option::Option<i32>: std::ops::Drop` > is not satisfied --> src/main.rs:4:5 | 4 | test_for_drop::<Option<i32>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Drop` is not implemented for `std::option::Option<i32>` | note: required by `test_for_drop` --> src/main.rs:1:1 | 1 | fn test_for_drop<T: Drop>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^