在 Rust 中管理生命周期:如何确保变量“足够长”存在?

问题描述 投票:0回答:1

我正在尝试使用 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

我已经尝试解决这个问题很长一段时间了,但没有成功。我仍在学习,因此任何额外的解释将不胜感激!

谢谢!

rust borrow-checker wgpu-rs winit
1个回答
0
投票

考虑到您想要管理多个窗口(实际上,即使您没有),这种借用问题的实际解决方案就是完全避免它。

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
表示它现在
不借用任何东西,而是拥有窗口的共享所有权

© www.soinside.com 2019 - 2024. All rights reserved.