Reputation: 33
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
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