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

Rust方法内&mut self生命周期问题:内部作用域赋值报错

WGPU + Winit v0.30 生命周期报错问题

问题描述

我正在结合wgpu与winit v0.30开发,按winit文档创建了窗口,但参考的learn wgpu教程用的是重构前的winit v0.29。作为Rust新手,入门书籍解决不了这个问题。

在主文件的if let语句中赋值self.state时,rust-analyzer提示生命周期不足,要求&mut self的生命周期'1必须长于'window。我懂生命周期基本概念,但不清楚结构体生命周期的工作机制,不知道报错原因。

代码展示

主文件代码

mod graphics;

use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
use winit::window::{Window, WindowId};

use graphics::State;

#[derive(Default)]
struct App<'window> {
    window: Option<Window>,
    state: Option<State<'window>>,
}

impl<'window> ApplicationHandler for App<'window> {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        let window = event_loop
            .create_window(Window::default_attributes())
            .unwrap();

        self.window = Some(window);
        if let Some(win) = &self.window {
            self.state = Some(State::new(win));
        }
    }

    fn window_event(
        &mut self,
        event_loop: &ActiveEventLoop,
        window_id: WindowId,
        event: WindowEvent,
    ) {
    }
}

fn main() {
    let event_loop = EventLoop::new().unwrap();
    event_loop.set_control_flow(ControlFlow::Wait);

    let mut app = App::default();
    event_loop.run_app(&mut app);
}

graphics模块代码

use pollster::FutureExt as _;

use wgpu::Backends;
use wgpu::Instance;
use wgpu::InstanceDescriptor;
use winit::{event::WindowEvent, window::Window};

pub struct State<'window> {
    surface: wgpu::Surface<'window>,
    device: wgpu::Device,
    queue: wgpu::Queue,
    config: wgpu::SurfaceConfiguration,
    size: winit::dpi::PhysicalSize<u32>,
    // The window must be declared after the surface so
    // it gets dropped after it as the surface contains
    // unsafe references to the window's resources.
    window: &'window Window,
}

报错原因

问题核心是生命周期绑定不匹配:

  • App<'window>的'window生命周期代表整个App实例的生命周期。
  • 在resumed方法中,&self.window取到的是临时引用,生命周期仅局限于resumed方法执行期间(标记为'1),远短于App的'window生命周期。
  • 编译器要求State<'window>持有的&'window Window必须和App的'window生命周期一致,但你传入的是短生命周期的临时引用,因此触发报错。

另外,原learn wgpu教程的v0.29版本用的是旧事件循环模式,不需要处理这种生命周期绑定,这也是适配新winit版本时遇到问题的关键原因。

解决方案

推荐两种适合新手的修改方式:

方式1:用Arc规避生命周期问题

使用Arc共享窗口所有权,让State和App同时持有窗口的引用,彻底规避生命周期绑定问题:

  1. 修改主文件:
use std::sync::Arc;

#[derive(Default)]
struct App {
    window: Option<Arc<Window>>,
    state: Option<State>,
}

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        let window = Arc::new(event_loop
            .create_window(Window::default_attributes())
            .unwrap());

        self.window = Some(window.clone());
        self.state = Some(State::new(window));
    }

    // 其他方法保持不变
}
  1. 修改graphics模块的State:
use std::sync::Arc;

pub struct State {
    surface: wgpu::Surface<'static>,
    device: wgpu::Device,
    queue: wgpu::Queue,
    config: wgpu::SurfaceConfiguration,
    size: winit::dpi::PhysicalSize<u32>,
    window: Arc<Window>,
}

impl State {
    pub fn new(window: Arc<Window>) -> Self {
        let size = window.inner_size();
        let instance = Instance::new(InstanceDescriptor {
            backends: Backends::all(),
            ..Default::default()
        });
        let surface = unsafe { instance.create_surface(window.clone()) }.unwrap();
        // 后续设备、队列、配置等初始化逻辑保持不变

        Self {
            surface,
            device,
            queue,
            config,
            size,
            window,
        }
    }
}

方式2:让State拥有Window所有权

修改State结构体直接持有Window的所有权,去掉生命周期参数:

// graphics模块的State修改后
pub struct State {
    surface: wgpu::Surface<'static>,
    device: wgpu::Device,
    queue: wgpu::Queue,
    config: wgpu::SurfaceConfiguration,
    size: winit::dpi::PhysicalSize<u32>,
    window: Window,
}

// 主文件的App和resumed方法修改
#[derive(Default)]
struct App {
    state: Option<State>,
}

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        let window = event_loop
            .create_window(Window::default_attributes())
            .unwrap();
        self.state = Some(State::new(window));
    }

    // 其他方法保持不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:57:08