为何出现‘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
| |
|rendereris a reference that is only valid in the method body
...
/ self.event_loop.run(move event, _, control_flow { if let Event::RedrawRequested(_) = event { let current_frame_time = Instant::now(); } }); ^ __________ rendererescapes the method body hereargument requires that '1must 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

