"错误:关闭可能比当前功能更长"但它不会比它活得更久

MrN*_*sco 11 closures lifetime rust

当我尝试编译以下代码时:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

error: closure may outlive the current function, but it borrows `should_end`, which is owned by the current function
Run Code Online (Sandbox Code Playgroud)

我不能简单地添加move到闭包中,因为我需要should_end稍后在主循环中使用.我的意思是,我能,但由于boolCopy,它只会影响到should_end瓶盖内,因而程序永远循环.

据我所知,由于input是在main函数中创建的,并且闭包存储在其中input,因此它不可能比当前函数寿命更长.有没有办法向Rust表达封闭不会比生命更长main?或者有可能我看不到关闭会比活动更长久main吗?在后一种情况下,有没有办法强迫它只活main

我是否需要重构我处理输入的方式,或者是否有某些方法可以使其工作.如果我需要重构,我在哪里可以看到Rust的一个很好的例子?

是一个简化版的围栏.我可能在其中犯了一个可能导致浏览器崩溃的错误.我碰巧遇到过一次,所以,要小心.

如果需要,的其余代码可用.所有相关信息都应该在main.rs或中input.rs.

oli*_*obk 10

问题不是你的关闭,而是add_handler方法.完全展开它看起来像这样:

fn add_handler<'a>(&'a mut self, handler: Box<FnMut(i32) + 'static>)
Run Code Online (Sandbox Code Playgroud)

如您所见,'static特征对象存在隐式约束.显然我们不希望这样,所以我们引入第二个生命周期'b:

fn add_handler<'a, 'b: 'a>(&'a mut self, handler: Box<FnMut(i32) + 'b>)
Run Code Online (Sandbox Code Playgroud)

由于您handler要将对象添加到Input::handlers字段中,因此该字段不能超过handler对象的范围.因此,我们还需要限制其寿命:

pub struct Input<'a> {
    handlers: Vec<Box<FnMut(i32) + 'a>>,
}
Run Code Online (Sandbox Code Playgroud)

这再次要求impl具有生命周期,我们可以在该add_handler方法中使用.

impl<'a> Input<'a> {
    ...
    pub fn add_handler(&mut self, handler: Box<FnMut(i32) + 'a>) {
        self.handlers.push(handler);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在剩下的就是使用a Cell来控制对你的should_end旗帜的访问.