Shcak
Shcak

Reputation: 33

Rust lifetimes : Static reference lives to short to be fed into a function?

I'm discovering rust and have a hard time with lifetimes.

For example, I am experimenting with GUIs a little :

#[macro_use]extern crate native_windows_gui as nwg;

use nwg::{Ui, Event, EventArgs};

nwg_template!(
    head: setup_ui<&'static str>,
    controls: [
        ("MainWindow", nwg_window!(title="Test1"; size=(180,50))),
        ("SetButton", nwg_button!(parent="MainWindow"; visible=false)),
        ("BackButton", nwg_button!(parent="MainWindow"; text="<"; position=(10,10); size=(30,30))),
        ("Text", nwg_textbox!(parent="MainWindow"; readonly=true; position=(40,10); size=(100,30))),
        ("NextButton", nwg_button!(parent="MainWindow"; text=">"; position=(140,10); size=(30,30)))
    ];
    events: [
        ("SetButton", "Set", Event::Click, |app,_,_,_| {
            let display = nwg_get_mut!(app; ("Text", nwg::TextBox));
            let index = nwg_get!(app; ("Index", &str));
            display.set_text(**index);
        }),
        ("BackButton", "Back", Event::Click, |_,_,_,_| {}),
        ("NextButton", "Next", Event::Click, |_,_,_,_| {})
    ];
    resources: [];
    values: [
        ("Index", "Test")
    ]
);

fn create_ui(data: &'static str) -> Result<Ui<&'static str>, nwg::Error> {
   let app: Ui<&'static str>;

    match Ui::new() {
        Ok(ui) => { app = ui; },
        Err(e) => { return Err(e) }
    }

    if let Err(e) = setup_ui(&app) {
        return Err(e);
    }

    app.pack_value(&"Data", &data);
    app.trigger(&"SetButton", Event::Click, EventArgs::None);

    if let Err(e) =app.commit() {
        Err(e)
    } else {
        Ok(app)
    }
}

fn main() {
    let data = "Foo";
    let _ui = create_ui(data).expect("Oups");
    nwg::dispatch_events();
}

I don't understand why in the function create_ui, data doesn't live long enough to be fed in app.pack_value().

It seems to me that the 'static lifetime would make it survive long enough.

But the compiler insits it dies at the end of create_ui and therefore cannot be used as app.pack_value("Data", &data);

What am I doing wrong ?

Upvotes: 3

Views: 1419

Answers (1)

Dan Hulme
Dan Hulme

Reputation: 15280

Without knowing the exact error, it's hard to be sure, but my guess is this:

fn create_ui(data: &'static str) -> Result<Ui<&'static str>, nwg::Error>

The parameter data will borrow a string of static lifetime. That is, the thing it points to (the string data) has static lifetime, but the reference itself has the lifetime of the function. Now let's look at the function in the native_windows_gui crate:

fn pack_value<T: Into<Box<T>> + 'static>(&self, id: &ID, value: T)

The parameter value has to have static lifetime. There are some other requirements too, but they're not relevant. Now back to your code:

app.pack_value(&"Data", &data);

You're passing pack_value a reference to data, which was already a reference. That is, the argument you're passing has type &&'static str. The outer reference (the one you're passing) doesn't have static lifetime: it lives only as long as your function.

The equivalent in C++ would be something like

result_type create_ui(static char *str) {
    Ui app = ...;
    app.pack_value(&"Data", &str);
}

This would compile fine in C++, but you're not passing the string, you're passing the address of the argument. This would compile fine but the behaviour would be undefined, and it would depend on what else is on the stack when that pointer is dereferenced. In Rust, instead of a hard-to-debug question, the compiler tells you what's wrong.

The solution is the same as it would be for C++: you need to remove the extra &, and pass the same reference you received:

app.pack_value(&"Data", data);

Upvotes: 2

Related Questions