Hi there,
I am new to Rust and I am struggling finding a way around the static lifetime constraint set for callbacks in the Cursive library (i.e. add_global_callback
, and thereafter button
). Looks like another user raised a similar help request recently. I have tried to provide a fully reproducible example, adapted from Cursive's main repo.
From some of the related discussions, I understand I can use smart pointers as a way around the static constraint. I had a go at this using RefCell
, unfortunately with no luck...
use cursive::event::{Event, Key};
use cursive::traits::*;
use cursive::views::{Dialog, EditView, OnEventView, TextArea};
use cursive::Cursive;
use std::cell::RefCell;
struct Item {
name: String
}
fn main() {
let mut siv = Cursive::default();
let item = RefCell::new(Item { name: "some name".to_string() });
siv.add_layer(
Dialog::new()
.title("Describe your issue")
.padding((1, 1, 1, 0))
.content(TextArea::new().with_id("text"))
.button("Ok", Cursive::quit),
);
siv.add_layer(Dialog::info("Hint: press Ctrl-F to find in text!"));
siv.add_global_callback(Event::CtrlChar('f'), |s| {
s.add_layer(
OnEventView::new(
Dialog::new()
.title("Change item")
.content(
EditView::new()
.with_id("edit")
.min_width(10),
)
.button("Ok", move |s| {
let text =
s.call_on_id("edit", |view: &mut EditView| {
view.get_content()
}).unwrap();
*item.borrow_mut() = Item {
name: text.to_string()
};
})
.dismiss_button("Cancel"),
).on_event(Event::Key(Key::Esc), |s| {
s.pop_layer();
}),
)
});
siv.run();
}
This doesn't compile:
error[E0373]: closure may outlive the current function, but it borrows `item`, which is owned by the current function
--> examples/text_area.rs:30:51
|
30 | siv.add_global_callback(Event::CtrlChar('f'), |s| {
| ^^^ may outlive borrowed value `item`
...
47 | *item.borrow_mut() = Item {
| ---- `item` is borrowed here
help: to force the closure to take ownership of `item` (and any other referenced variables), use the `move` keyword
|
30 | siv.add_global_callback(Event::CtrlChar('f'), move |s| {
| ^^^^^^^^
When I try to follow the compiler tip and the move
keyword, I endup with another error:
error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
--> examples/text_area.rs:42:35
|
15 | let item = RefCell::new(Item { name: "some name".to_string() });
| ---- captured outer variable
...
42 | .button("Ok", move |s| {
| ^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure