You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何出现‘borrowed data escapes outside of method’错误?求解决方案

问题

我有一个需要在事件循环中修改的renderer变量,但在App结构体的run函数中,事件循环始终报borrowed data escapes outside of method错误。我需要在保留运行时调整renderer值能力的前提下解决该问题,目前看到的方案都会产生某种形式的副本,这不是我想要的。

完整错误信息

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
...

/ self.event_loop.run(moveevent, _, control_flow{
if let Event::RedrawRequested(_) = event {
let current_frame_time = Instant::now();
}
});
^
__________renderer escapes the method body here
argument requires that '1 must outlive 'static

简化代码(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();
            }
        });
    }
}
解决方案

核心原因

event_loop.run()的闭包要求捕获的变量具有'static生命周期——因为事件循环会持续运行到程序退出,闭包需要存活整个程序生命周期。但你传入的renderer是方法内的可变引用,生命周期仅局限于run方法内部,因此编译器判定它逃逸了方法作用域,触发报错。

可行方案(无副本,保留运行时修改能力)

方案1:将Renderer所有权转移到App结构体

如果业务逻辑允许,直接把Renderer作为App的成员变量:

pub struct App {
    renderer: Renderer, // 直接持有所有权
    // 其他成员...
}

// 调整初始化逻辑,将Renderer传入App
impl App {
    pub fn new(renderer: Renderer) -> Result<Self, pixels::Error> {
        // 初始化其他成员
        Ok(Self { renderer, /* ... */ })
    }

    pub fn run(mut self) -> Result<(), pixels::Error> {
        let mut previous_frame_time = Instant::now();

        self.event_loop.run(move |event, _, control_flow| {
            if let Event::RedrawRequested(_) = event {
                // 直接使用self.renderer,无需外部引用
                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;
                self.renderer.on_update(timestep, &self.input);

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

            // 其他逻辑
            self.window.request_redraw();
        });
    }
}

这种方式完全没有副本,你可以通过给App添加方法(比如pub fn get_mut_renderer(&mut self) -> &mut Renderer)来实现运行时调整renderer的需求。

方案2:用Arc<Mutex<Renderer>>共享所有权

如果必须在App外部持有Renderer的访问权(比如多组件需要共享),可以用原子引用计数+互斥锁实现线程安全共享:

// 调用run时传入Arc<Mutex<Renderer>>
pub fn run(mut self, renderer: Arc<Mutex<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;

            // 锁定Mutex获取可变引用
            let mut renderer = renderer.lock().unwrap();
            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();
    });
}

该方式不会产生Renderer副本,仅增加线程安全开销。如果是单线程场景,可用Rc<RefCell<Renderer>>替代,进一步降低开销。外部代码通过持有同一个Arc<Mutex<Renderer>>实例,即可实现运行时修改renderer。

方案3:用闭包封装修改逻辑

如果仅需在外部触发renderer修改,不需要直接持有它,可将修改逻辑封装为闭包传入:

pub fn run<F>(mut self, mut renderer: Renderer, mut update_renderer: F) -> Result<(), pixels::Error>
where
    F: FnMut(&mut Renderer) + 'static,
{
    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;

            // 先执行外部传入的修改逻辑
            update_renderer(&mut renderer);
            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();
    });
}

此方式将Renderer所有权转移到闭包中,外部通过update_renderer闭包间接修改renderer,同样无副本产生。


内容的提问来源于stack exchange,提问作者Question Asker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:45:29