Force struct to be moved into a closure

Question is simple - how to force struct to be moved into a closure and not just its field copied?

In my case I receive struct from the C code with some data and a release function. I need to release data only after callback is gets triggered.

struct Abc {
    ptr: usize,
    free: fn(usize),
}

impl Drop for Abc {
    fn drop(&mut self) {
        (self.free)(self.ptr);
    }
}

fn test(data: Abc) -> impl Fn() -> String {
    move || {
        format!("{}", data.ptr) // do something with ptr
    }
}

fn main() {
    let abc = Abc {
        ptr: 10,
        free: |_| {},
    };
    let closure = test(abc);
    closure();
    closure();
    closure();
}

The problem is that Rust for some reason copies the value of ptr and drops struct before closure is getting called instead of keeping struct alive until closure dies itself.

When I inspect a closure, I can see that indeed only a field gets copied instead of the struct.
image

This should do it:

fn test(data: Abc) -> impl Fn() -> String {
    move || {
        let data = data;
        format!("{}", data.ptr) // do something with ptr
    }
}

@alice I didn't try it expecting the same result... And it is working. Thanks.

Well... Actually it should be let data = &data; instead :slight_smile:

Both should work, but I find that let data = data; more clearly emphasizes the intent behind the code.

let data = data; doesn't work because it can't move out a data from the Fn closure.

I see.

The reason is the "disjoint capture in closures" feature of the 2021 edition. That can definitely be surprising for cases like yours where the field is copyable, so move doesn't need to capture as much.

1 Like

Thanks for the link!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.