为什么我会收到“借用的数据在方法之外逃逸”错误?

Why do I get a "borrowed data escapes outside of method" error?

提问人:Question Asker 提问时间:6/29/2023 最后编辑:Question Asker 更新时间:6/29/2023 访问量:1186

问:

我有一个变量,我必须在事件循环中编辑它。问题是我在结构函数中不断收到相同的事件循环错误。如何在仍然能够调整 over runtime 的值的情况下解决此问题?我看到的所有解决方案都导致某种形式的副本被传递,这不是我需要的。感谢您的帮助!rendererborrowed data escapes outside of methodrunApprenderer

完全错误:

error[E0521]: borrowed data escapes outside of method
  --> src/app.rs:54:9
   |
50 |       pub fn run(mut self, renderer: &mut Renderer) -> Result<(), pixels::Error> {
   |                            --------  - let's call the lifetime of this reference `'1`
   |                            |
   |                            `renderer` is a reference that is only valid in the method body
...
54 | /         self.event_loop.run(move |event, _, control_flow| {
55 | |             if let Event::RedrawRequested(_) = event {
56 | |
57 | |                 let current_frame_time = Instant::now();
...  |
84 | |             }
85 | |         });
   | |          ^
   | |          |
   | |__________`renderer` escapes the method body here
   |            argument requires that `'1` must outlive `'static`

对于完整的长代码,这是我的 GitHub 存储库:https://github.com/KGL8/RayTracingPaper/tree/working_snapshot

我 App.rs 的缩短版本:

pub struct App {
    // ***
}

impl App {
    pub fn new() -> Result<Self, pixels::Error> {
        // ***
    }

    pub fn create_window(event_loop: &EventLoop<()>) -> Window {
        // ***
    }

    pub fn run(mut self, renderer: &mut Renderer) -> Result<(), pixels::Error> {

        let mut previous_frame_time = Instant::now();

        self.event_loop.run(move |event, _, control_flow| {
            if let Event::RedrawRequested(_) = event {

                let current_frame_time = Instant::now();
                let timestep = current_frame_time.duration_since(previous_frame_time).as_secs_f32();
                previous_frame_time = current_frame_time;
                renderer.on_update(timestep, &self.input);

                if let Err(err) = renderer.render(&mut self.pixels) {
                    log_error("renderer.draw_frame", err);
                    *control_flow = ControlFlow::Exit;
                    return;
                }
            }

            // ***

                self.window.request_redraw();
            }
        });
    }
}
循环 参考 借用检查器 可变

评论

0赞 isaactfa 6/29/2023
如果没有完整的错误消息,很难说,但我猜您传递到的闭包不允许借用任何数据,因此它不能使用,因为它是引用。如何解决此问题在某种程度上取决于为什么首先通过引用而不是按值传递渲染器。 永远不会返回,所以我不确定不给它所有权是否有好处。event_loop.runrendererevent_loop.runrenderer
0赞 Question Asker 6/29/2023
我对所有权的东西不太熟悉......我是编程新手。目前,渲染器在我的 main 函数中声明并传递给应用程序结构:let mut renderer = Renderer::new(window, camera); => app.run(&mut renderer)?;

答:

3赞 chmod777 6/29/2023 #1

您将 ,这是一个可变的引用,传递到 ,这是具有生命周期的闭包。rendererevent_loop.run'static

让我们看一下EventLoop::run

    pub fn run<F>(self, event_handler: F) -> !
    where
        F: 'static + FnMut(Event<'_, T>, [ ... ] ),

该部分的意思是“这个参数是一个具有静态生存期的闭包”。稍微分解一下:'static + FnMut

  • 闭包很像函数,但它与调用函数所需的所有其他变量“捆绑在一起”
  • 'static是一个特殊的生命周期限制,它告诉 Rust 我们的闭包不会借用任何非生命周期的数据'static

由于事件循环想要无限期地调用,因此只要程序在运行,就必须继续存在。 您正确地使用了闭包,这会导致闭包中引用的所有变量被捕获并移动到闭包中(这就是上面的“捆绑”)。 是有问题的,因为它是一个引用,所以我们不能把它移到闭包中。event_handlerevent_handlermoverenderer

我们有一个闭包,它必须一直存在到程序结束,但包括一个引用,一旦程序结束就会消失!这就是编译器所说的含义。borrowed data escapes outside of method

为了解决这个问题,我们需要向编译器承诺渲染器会一直存在,直到程序退出。最简单的方法就是做它, 在'staticApp::run()

pub fn run(mut self, renderer: &'static mut Renderer)

然后,当您实例化时,请使用lazy_staticRenderer

lazy_static! {
    static ref RENDERER: Renderer = Renderer::new();
}

评论

3赞 PatientPenguin 6/29/2023
’static does not mean that the data lives for the duration of the program. That’s a common misconception that you can find here. It means that the data doesn’t borrow anything that does not have a lifetime.'static
0赞 chmod777 6/30/2023
TIL! appreciate the correction