Rust中不派生Clone trait如何强制传值?Window结构体返回报错求助
问题
我是Rust新手,尝试返回如下Window结构体:
pub struct Window<'a> { ev_loop: EventLoop<()>, window_builder: WindowBuilder, context_builder: ContextBuilder<'a, NotCurrent>, display: Display }
并通过以下函数返回该结构体:
pub fn init_lib () -> Window<'static> { let event_loop = glutin::event_loop::EventLoop::new(); let wb = glutin::window::WindowBuilder::new(); let cb = glutin::ContextBuilder::new(); let display = glium::Display::new(wb, cb, &event_loop).unwrap(); return Window { ev_loop: event_loop, window_builder: wb, context_builder: cb, display: display } }
但返回wb作为window_builder、cb作为context_builder时出现错误:
use of moved value: `cb` value used here after moverustcE0382 lib.rs(32, 43): value moved here lib.rs(31, 9): move occurs because `cb` has type `ContextBuilder<'_, NotCurrent>`, which does not implement the `Copy` trait
我使用的是glium库,无法修改源码,请问如何解决?另外,如何在Rust中不派生Clone trait的情况下强制传值?
解决方案
针对当前glium场景的解决办法
问题核心是glium::Display::new会转移(move)传入的WindowBuilder和ContextBuilder的所有权,所以这两个变量在调用完new之后就不能再被使用了。你有两种可行的处理方式:
- 放弃存储原始的构建器实例
如果你的Window结构体不需要保留window_builder和context_builder,直接移除这两个字段即可:
pub struct Window<'a> { ev_loop: EventLoop<()>, display: Display } pub fn init_lib () -> Window<'static> { let event_loop = glutin::event_loop::EventLoop::new(); let wb = glutin::window::WindowBuilder::new(); let cb = glutin::ContextBuilder::new(); let display = glium::Display::new(wb, cb, &event_loop).unwrap(); Window { ev_loop: event_loop, display: display } }
- 克隆构建器再传入
Display::newWindowBuilder和ContextBuilder本身已经实现了Clonetrait(glium/glutin的公开API设计如此),可以先克隆一份用于创建Display,保留原始实例存入结构体:
pub fn init_lib () -> Window<'static> { let event_loop = glutin::event_loop::EventLoop::new(); let wb = glutin::window::WindowBuilder::new(); let cb = glutin::ContextBuilder::new(); // 克隆构建器用于创建Display,原始实例保留 let display = glium::Display::new(wb.clone(), cb.clone(), &event_loop).unwrap(); Window { ev_loop: event_loop, window_builder: wb, context_builder: cb, display: display } }
关于“不派生Clone强制传值”的说明
在Rust中,不存在“不实现Clone就强制传值”的语法——所有权规则是语言的核心约束,目的是避免内存安全问题。如果一个类型没有实现Copy或Clone,你只能通过以下方式转移或复用它:
- 转移所有权(move):变量只能被move一次,之后原变量不可再用;
- 借用(borrow):通过引用
&T或可变引用&mut T临时访问变量,但所有权仍属于原持有者; - 使用智能指针:比如
Rc<T>或Arc<T>,允许多个所有者共享同一实例,但会带来运行时开销,且需要类型满足Sync/Send(根据场景)。
回到你的场景,WindowBuilder和ContextBuilder已经实现了Clone,直接用克隆是最简洁且符合API设计的方案。
内容的提问来源于stack exchange,提问作者NaniNoni
相关产品推荐
相关产品推荐

