Galaxy
Galaxy

Reputation: 1279

Does setting an Option instance from Some to None trigger dropping of the inner value?

I have the code:

struct Foo {}

impl Default for Foo {
    fn default() -> Self {
        Self {}
    }
}

impl Drop for Foo {
    fn drop(&mut self) {
        // Do something
    }
}

fn main() {
    {
        let foo = Some(Foo::default());
        let foo = None; // Would this line trigger `Foo::drop`?
    };
    {
        let mut foo = Some(Foo::default());
        foo = None; // Would this line trigger `Foo::drop`?
    };
}

Are the resources occupied by foos released properly?

The first situation (variable overwritten) will not trigger drop, so I added the second situation, in which I'm also confused.

Upvotes: 6

Views: 1666

Answers (2)

Jan Hudec
Jan Hudec

Reputation: 76346

let foo = Some(Foo::default());
let foo = None; // Would this line trigger `Foo::drop`?

No, the end of the block will.

Remember that let is a variable declaration, so the second line is not modifying the first foo, it is creating a new foo that shadows the former. But it still exists (and could be accessed if you created a reference to it before the second let) until the end of the block, so it will be dropped at end of the block.

If you want to actually change the variable, you have to do

let mut foo = Some(Foo::default());
foo = None;

Now it will trigger the drop immediately, because the old value is being overwritten, so it has to drop it.

Upvotes: 7

Akiner Alkan
Akiner Alkan

Reputation: 6918

Unless you explicitly notate your variable name as _ it is dropped when the scope has finished.

In your case, variables will be released when the relevant scope is ended.

Since you implement Drop trait for Foo explicitly. It will override the drop behavior and call your drop function:

fn main() {
    let _: Option<Foo> = Some(Foo::default()); // Since variable name is '_' it will be dropped automatically.

    {
        let foo: Option<Foo> = Some(Foo::default());
        let foo: Option<Foo> = None;
        println!("Inner Scope Finishing. Going to drop inner scope variables.");
    } // Inner scope is finished dropping the inner scope variables.

    let main_foo: Option<Foo> = Some(Foo::default());
    let main_foo: Option<Foo> = None;
    println!("Main Scope Finishing. Going to drop main scope variables.");
} // Main is finished dropping the main scope variables

Playground to show the behavior.

Upvotes: 2

Related Questions