Search code examples
rustdestructortraits

Where is it documented that Option<T> is Drop?


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);
}

Playground

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?


Solution

  • 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, Bars 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>>();
    }
    

    Playground

    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>() {}
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^