When I try to compile the following code:
fn main() {
(...)
let mut should_end = false;
let mut input = Input::new(ctx);
input.add_handler(Box::new(|evt| {
match evt {
&Event::Quit{..} => {
should_end = true;
}
_ => {}
}
}));
while !should_end {
input.handle();
}
}
pub struct Input {
handlers: Vec<Box<FnMut(i32)>>,
}
impl Input {
pub fn new() -> Self {
Input {handlers: Vec::new()}
}
pub fn handle(&mut self) {
for a in vec![21,0,3,12,1] {
for handler in &mut self.handlers {
handler(a);
}
}
}
pub fn add_handler(&mut self, handler: Box<FnMut(i32)>) {
self.handlers.push(handler);
}
}
I get this error:
error: closure may outlive the current function, but it borrows `should_end`, which is owned by the current function
I can't simply add move
to the closure, because I need to use should_end
later in the main loop. I mean, I can, but since bool
is Copy
, it will only affect the should_end
inside the closure, and thus the program loops forever.
As far as I understand, since input
is created in the main function, and the closure is stored in input
, it couldn't possibly outlive the current function. Is there a way to express to Rust that the closure won't outlive main
? Or is there a possibility that I can't see that the closure will outlive main
? In the latter case, it there a way to force it to live only as long as main
?
Do I need to refactor the way I'm handling input, or is there some way I can make this work. If I need to refactor, where can I look to see a good example of this in Rust?
Here's a playpen of a simplified version. It is possible I made a mistake in it that could crash your browser. I happened to me once, so, beware.
In case it is needed, the rest of my code is available. All the relevant info should be in either main.rs
or input.rs
.
The problem is not your closure, but the
add_handler
method. Fully expanded it would look like this:As you can see, there's an implicit
'static
bound on the trait object. Obviously we don't want that, so we introduce a second lifetime'b
:Since you are adding the
handler
object to theInput::handlers
field, that field cannot outlive the scope of thehandler
object. Thus we also need to limit its lifetime:This again requires the impl to have a lifetime, which we can use in the
add_handler
method.Now all that's left is using a
Cell
to control access to yourshould_end
flag.Here is an example of the fixed code: