我正在尝试使用 Rust 编写一个渲染引擎库,使用
wgpu
和 winit
,并且一直在遵循“学习 WGPU”教程。不幸的是,事实证明,create_surface
箱中的一些不安全代码(
wgpu
)很难解决!
我的
Window
结构源自“学习 WGPU”教程中定义的 State
结构(参见此处):
// This is pseudo-code.
struct Window<'a> {
surface: wgpu::Surface<'a>,
window: &'a winit::window::Window,
// Other stuff...
}
生命周期需要为:
“...表面包含对窗口的不安全引用 资源。”
这就是我的问题开始的地方。
现在,我打算拥有一个“多窗口兼容”库,因此,使用
windows
管理 HashMap
,如下所示:
// This is pseudo-code.
struct App<'a> {
windows: HashMap<winit::window::WindowId, crate::window::Window<'a>>,
// Other stuff...
}
现在,最初,我有一个名为
App
的函数(在 create_window
中),它会创建 winit::window::Window
和 crate::window::Window
(在一个函数中),然后将其存储在 windows
HashMap
中,像这样:
// This is pseudo-code.
fn create_window(&mut self, title: &str, width: u32, height: u32) {
// Create `winit` window...
let window = ?;
let surface = instance.create_surface(window).unwrap();
self.windows.insert(window.id(), crate::window::Window::new(surface, &window));
}
这个实现(显然)不起作用,因为
window
在函数末尾被删除,因此,crate::window::Window
对它的引用变成了invalid(“借用时临时值被删除”) .
OK,所以我将
winit::window::Window
的创建移到 create_window
函数之外,以确保它“活得足够长”,如下所示:
// This is pseudo-code.
fn add_window(&mut self, window: &'a winit::window::Window) {
let surface = instance.create_surface(window).unwrap();
self.windows.insert(window.id(), crate::window::Window::new(surface, &window));
}
然后我尝试使用示例来测试
add_window
函数:
// This is pseudo-code.
// This is an example for my library ('examples/window-example/main.rs')...
fn main() {
let mut app = App::new(ControlFlow::Poll).expect("Failed to create app.");
// Create `winit` window...
let window = ?;
app.add_window(&window).expect("Failed to create window.");
app.run().expect("Failed to run app.");
}
问题是,我仍然遇到同样的错误(“
window
活得不够长”)!但是(据我所知),window
应该和程序本身一样长,因为它只在main
结束时被删除,因此应该活得足够长以供crate::window::Window
的(或者更确切地说,wgpu
的)surface
?
我已经尝试解决这个问题很长一段时间了,但没有成功。我仍在学习,因此任何额外的解释将不胜感激!
谢谢!
考虑到您想要管理多个窗口(实际上,即使您没有),这种借用问题的实际解决方案就是完全避免它。
create_surface()
实际上并不需要窗口的 reference,并且使用引用在您发现的方式中是有问题的,所以不要这样做。您可以使用不同类型的指针;特别是,Arc
。
struct Window {
surface: wgpu::Surface<'static>,
window: Arc<winit::window::Window>,
}
fn create_window(&mut self, title: &str, width: u32, height: u32) {
// Create `winit` window owned by an `Arc`
let window = Arc::new(
event_loop.create_window(Window::default_attributes()).unwrap()
);
let surface = instance.create_surface(window.clone()).unwrap();
self.windows.insert(window.id(), crate::window::Window::new(surface, window));
}
在这种情况下,'static
类型中的生命周期
Surface
表示它现在不借用任何东西,而是拥有窗口的共享所有权。