Lifetime of reference outlives lifetime of borrowed content

Hello

I'm trying to write a Gtk application. I have one function called build_ui to build the start-screen. Now I want to call a second function when a button gets clicked, however that called function has the app variable as parameter.

This is my code:

pub fn build_ui(app: &'static gtk::Application) {
    //[More code here]
    //...

    //Event bindings
    btn_add.connect_clicked(|button| {
        println!("Add button clicked");
        second_function(app);
    });
   
   //More code here....
}

pub fn second_function(app: &gtk::Application) {
    //Doing things here using the app-parameter...
}

fn main() {
    
    let app = gtk::Application::new(Some("com.cat.manager"), Default::default()).expect("Gtk initialization failed...");
    
    app.connect_activate(|app| {
        user_interface::build_ui(app);
    });

    app.run(&args().collect::<Vec<_>>());

}

But it gives this error:

    error[E0312]: lifetime of reference outlives lifetime of borrowed content...
  --> src/main.rs:84:34
   |
84 |         user_interface::build_ui(app);
   |                                  ^^^
   |

I had to make the parameter in build_ui static, because the compiler told me so.
The purpose of the second_function is to remove all the labels, buttons, objects,... in the window to replace them with other ones.

Thanks!

The original error tells you why it suggests a static lifetime on your function:

error[E0621]: explicit lifetime required in the type of `app`
  --> src/main.rs:12:13
   |
6  | pub fn build_ui(app: &gtk::Application) {
   |                      ----------------- help: add explicit lifetime `'static` to the type of `app`: `&'static gtk::auto::application::Application`
...
12 |     btn_add.connect_clicked(|button| {
   |             ^^^^^^^^^^^^^^^ lifetime `'static` required

And indeed, gtk::ButtonExt::connect_click has a 'static lifetime bound on the Fn trait bound.

This means that every reference moved into the closure must live as long as the entire executable. You can hack around this with Rc to avoid using static borrows... But it really isn't pretty. Here's what I came up with (anyone feel free to speak up if there is a better way!)

Spoiler alert! :D
use gio::prelude::*;
use gtk::prelude::*;

use std::env::args;
use std::rc::Rc;

pub fn build_ui<T>(app: Rc<T>)
where
    T: glib::IsA<gtk::Application>,
{
    let win = gtk::ApplicationWindow::new(app.as_ref());

    let btn_add = gtk::Button::new_with_label("Click me!");

    //Event bindings
    btn_add.connect_clicked(move |_button| {
        println!("Add button clicked");

        let app_clone = Rc::clone(&app);
        second_function(app_clone);
    });

    win.add(&btn_add);
}

pub fn second_function<T>(_app: Rc<T>)
where
    T: glib::IsA<gtk::Application>,
{
    //Doing things here using the app-parameter...
}

fn main() {
    let app = gtk::Application::new(Some("com.cat.manager"), Default::default())
        .expect("Gtk initialization failed...");

    let app = Rc::new(app);
    let app_clone = Rc::clone(&app);

    app.connect_activate(move |_app| {
        build_ui(Rc::clone(&app_clone));
    });

    app.run(&args().collect::<Vec<_>>());
}

The double-Rc-clone in the connect_activate closure is intentional. It's necessary because of the Fn trait bound.

This solution makes me kind of ill. :face_vomiting: I hope there is a better way...

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.