当我尝试编译以下代码时:
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);
}
}
我收到此错误:
error: closure may outlive the current function, but it borrows `should_end`, which is owned by the current function
我不能简单地将move
添加到闭包中,因为我需要稍后在主循环中使用should_end
。我的意思是,我可以,但由于bool
是Copy
,它只会影响闭包内的should_end
,因此程序会永远循环。
据我所知,由于input
是在main函数中创建的,而闭包存储在input
中,因此它不可能比当前函数寿命更长。有没有办法向Rust表达封闭不会比main
更长寿?或者是否有可能我看不到封闭会比main
更长?在后一种情况下,有一种方法可以强制它只在main
生效吗?
我是否需要重构我处理输入的方式,或者是否有某些方法可以使其工作。如果我需要重构,我在哪里可以看到Rust的一个很好的例子?
这是a playpen of a simplified version。我可能在其中犯了一个可能导致浏览器崩溃的错误。我碰巧遇到过一次,所以,要小心。
如果需要,my code is available的其余部分。所有相关信息均应位于main.rs
或input.rs
。
答案 0 :(得分:10)
问题不是关闭,而是add_handler
方法。完全展开它看起来像这样:
fn add_handler<'a>(&'a mut self, handler: Box<FnMut(i32) + 'static>)
正如您所看到的,特征对象上存在隐式'static
绑定。显然我们不想要那样,所以我们引入了第二个生命周期'b
:
fn add_handler<'a, 'b: 'a>(&'a mut self, handler: Box<FnMut(i32) + 'b>)
由于您要将handler
对象添加到Input::handlers
字段,因此该字段不能超过handler
对象的范围。因此,我们还需要限制其生命周期:
pub struct Input<'a> {
handlers: Vec<Box<FnMut(i32) + 'a>>,
}
这再次要求impl具有生命周期,我们可以在add_handler
方法中使用它。
impl<'a> Input<'a> {
...
pub fn add_handler(&mut self, handler: Box<FnMut(i32) + 'a>) {
self.handlers.push(handler);
}
}
现在剩下的就是使用Cell
来控制对should_end
标记的访问。
答案 1 :(得分:0)
以下是an example of the fixed code:
use std::cell::Cell;
fn main() {
let should_end = Cell::new(false);
let mut input = Input::new();
input.add_handler(Box::new(|a| {
match a {
1 => {
should_end.set(true);
}
_ => {
println!("{} {}", a, should_end.get())
}
}
}));
let mut fail_safe = 0;
while !should_end.get() {
if fail_safe > 20 {break;}
input.handle();
fail_safe += 1;
}
}
pub struct Input<'a> {
handlers: Vec<Box<FnMut(i32) + 'a>>,
}
impl<'a> Input<'a> {
pub fn new() -> Self {
Input {handlers: Vec::new()}
}
pub fn handle(&mut self) {
for a in vec![21,0,3,12,1,2] {// it will print the 2, but it won't loop again
for handler in &mut self.handlers {
handler(a);
}
}
}
pub fn add_handler(&mut self, handler: Box<FnMut(i32) + 'a>) {
self.handlers.push(handler);
}
}