我在尝试winit(和wgpu)库的时候,在一个闭包里对数据可空引用进行重新赋值操作,出现了如题目所示的问题。我把它抽离出一个简单的模型如下:
// 这个Color 代表了被引用的数据
#[derive(Debug)]
struct Color {
x: u32,
y: u64,
}
// 这个State代表了持有数据的引用的一方
#[derive(Debug)]
struct State<'a> {
v: Option<&'a Color>,
}
// 这个App模拟了winit库里的EventLoop
// run方法的签名是直接搬过来的,即我不能改动这个函数签名
struct App;
impl App {
fn run<F>(self, mut event_handler: F)
where
F: 'static + FnMut(u32),
{
// 简化对闭包处理的模拟,直接调用
event_handler(10);
}
}
// 这个app_run模拟包含了使用人家run接口的方法
fn app_run(mut state: State) {
let app = App;
let color = Color { x: 1, y: 1 };
app.run(move |_| {
// 这里对使用情况进行模拟
if true {
state.v = Some(&color); // 这一句引发问题。
}else{
state.v = None;
}
})
}
fn main() {
let sate = State{ v: None };
app_run(sate);
}
这里是playground
原问题代码如下
// State里有一个HashMap类型的render_pipeline,对它使用get得到数据的引用
// Config里current_pipeline是对数据的可空引用。初始化为None
fn app_run<T>(window: Window, event_loop: EventLoop<T>, mut state: State, mut config: Config) {
event_loop.run(move |ev, _tgt, control| match ev {
Event::WindowEvent {
window_id,
ref event,
} if window.id() == window_id => match event {
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Space),
..
},
..
} => match config.current_pipeline {
Some(v) => {
if let Some(nv) = state.render_pipeline.get("base pipeline") {
if std::ptr::eq(v, nv) {
// 如果没有这种赋值是可以运行的。
config.current_pipeline = state.render_pipeline.get("color pipeline");
};
} else {
config.current_pipeline = state.render_pipeline.get("base pipeline");
}
}
None => config.current_pipeline = state.render_pipeline.get("base pipeline"),
},
_ => {}
},
_ => {}
});
}
1
共 2 条评论, 1 页
评论区
写评论'static
意味着State内不能有引用,即不依赖其它变量生命周期FnMut
意味着State里color不引用的话就要实现Clone或Copy,以便捕获后多次调用你的代码有两处错误:
fn app_run(mut state: State<'1>)
,state 包含外部的引用 &'1,所以你不可能让 state 得到函数内的 color 变量的引用。要解决你遇到的生命周期的问题,必须重构代码(从类型到逻辑都要考虑到),尤其不能让
F: 'static + FnMut(u32)
闭包捕获非 'static 的引用或者非 'static 生命周期参数的类型。