Idiomatic approach to call function at the end of the scope (assume I have no object with `Drop`)

There is an API for some external resource, something like that

struct SomeOpaqueType(u8);


fn create_something() -> SomeOpaqueType {
    SomeOpaqueType(42)
}

fn drop_something(something: SomeOpaqueType) {
    println!("Dropping {}", something.0);
}

That could be open / close function in my OS or whatever.
Once you call create_something, you MUST call drop_something.

I can could call it manually,

    let something = create_something();
    drop_something(something);

however panic might break things

    let something = create_something();
    panic!("AAA");
    drop_something(something); //Never called

The natural approach is to wrap it with Drop 'able object. But that looks like a lot of boilerplate.

I can imagine some universal thing like

struct Closer<T: Fn()> {
    close_me: T,
}

impl<T: Fn()> Drop for Closer<T> {
    fn drop(&mut self) {
        (self.close_me)();
    }
}

///
    let something = create_something();
    let _ = Closer {
        close_me: || { drop_something(something) }
    };

but it doesn't look nice either and I will have problems since something would be moved.

In C++ they use BOOST_SCOPE_EXIT_END, in Go they use defer, what is the right thing to do in Rust?

Generally the pattern would be to implement Drop for the type that needs cleanup, and not for a type that runs a function on it.

If you still prefer something that looks like a defer you can use the scopeguard crate. In particular the scopeguard::guard will also let you take ownership when the scope ends.

4 Likes