Problem passing object into closure

I have a method that runs an egui event loop but I want to pass an extra parameter into the closure (self.icc).

pub fn ui_run(&mut self) {
        //self.i_ui.run_event_loop();
        let options = eframe::NativeOptions::default();

        eframe::run_native(
            "egui Rust SDR",
            options,
            Box::new(|cc| Box::new(ui::egui_ui::MyApp::new(cc, self.i_cc.clone()))),
        );
    }

I've tried lots of ways but can't figure it out. I've done this before by assigning and doing a move but nothing seems to work with this one.

error: lifetime may not live long enough
--> src\app.rs:258:13
|
251 | pub fn ui_run(&mut self) {
| - let's call the lifetime of this reference '1
...
258 | Box::new(|cc| Box::new(ui::egui_ui::MyApp::new(cc, self.i_cc.clone()))),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that '1 must outlive 'static

The point of cloning in this kind of situation is to make a copy that can live on its own and is not borrowing from anything. But by writing self.i_cc.clone() inside the closure, you're deferring the conversion from borrow to owned until it's too late to help. As a general rule, when you're cloning for this purpose, the clone must happen outside the closure.

    pub fn ui_run(&mut self) {
        let options = eframe::NativeOptions::default();
        let i_cc = self.i_cc.clone();

        eframe::run_native(
            "egui Rust SDR",
            options,
            Box::new(move |cc| Box::new(ui::egui_ui::MyApp::new(cc, i_cc))),
        );
    }

I also changed the closure to a move closure. Depending on the type of i_cc and of MyApp::new, this may or may not make a difference, but it's usually the right choice in these situations. move asks the closure to never capture anything by reference, only by move, so it ensures that the closure owns i_cc and will satisfy the 'static bound, rather than borrowing i_cc from the function scope.

3 Likes

Thank you. I tried putting the clone before the || as that had worked before but didn't think to put it outside the call. I think this is a situation where the compiler could be more helpful as the "1 must outlive static" is difficult to understand for me anyway. I live and learn.

Yeah, that "must outlive 'static lifetime" compile error can be pretty hard to grok unless you've seen it before. Especially when combined with closures.

In essence, the compiler is trying to say that whatever you pass into the closure must be able to live as long as it needs to (i.e. it could store the value in a field and use it after the function call ends without worrying about dangling references). In practice, this means you can't have any references and must move ownership of any external objects into the closure.

The easiest way to avoid having any references is to clone whatever your closure is using, like @kpried suggested.