我正在使用sdl2 crate,我正在尝试创建一个简单的"上下文";带有计时器的对象。我有以下代码
extern crate sdl2;
struct Ctx<'a, 'b> {
timer: sdl2::timer::Timer<'a, 'b>,
}
impl<'a,'b> Ctx<'a, 'b> {
pub fn new() -> Ctx<'a,'b> {
let sdl_context = sdl2::init().unwrap();
let timer_subsystem = sdl_context.timer().unwrap();
let timer = timer_subsystem.add_timer(100, Box::new(|| -> u32 { 100 }));
Ctx { timer }
}
}
pub fn main() {
let _ = Ctx::new();
}
问题是add_timer()似乎借用了timer_子系统对象,它阻止了计时器从函数中移出。
error[E0515]: cannot return value referencing local variable `timer_subsystem`
--> src/main.rs:13:9
|
11 | let timer = timer_subsystem.add_timer(100, Box::new(|| -> u32 { 100 }));
| ----------------------------------------------------------- `timer_subsystem` is borrowed here
12 |
13 | Ctx { timer }
| ^^^^^^^^^^^^^ returns a value referencing data owned by the current function
然而,如果我查看add_timer()
,我不明白为什么引用被认为仍然存在。事实上,self
引用根本没有在函数中使用:https://docs.rs/sdl2/latest/src/sdl2/timer.rs.html 17-32
pub fn add_timer<'b, 'c>(&'b self, delay: u32, callback: TimerCallback<'c>) -> Timer<'b, 'c> {
unsafe {
let callback = Box::new(callback);
let timer_id = sys::SDL_AddTimer(
delay,
Some(c_timer_callback),
mem::transmute_copy(&callback),
);
Timer {
callback: Some(callback),
raw: timer_id,
_marker: PhantomData,
}
}
}
我试图把timer
和timer_subsystem
到Ctx
(以确保他们的寿命是相同的),但它没有帮助。两者都没有使用Box<>
包装它们(以防止在timer_子系统被移动后出现悬空指针),但两者都不起作用。
为什么我在这里引用了本地数据,我如何才能正确返回timer
对象?
秘密在PhantomData
。Timer
内部声明的完整类型是PhantomData<&'b ()>
,'b
在add_timer()
中指定为&'b self
。这将返回的Timer
的生命周期与TimerSubsystem
的生命周期绑定在一起。这是因为当子系统被丢弃时,它被关闭,并且之后不允许访问计时器。
最好的选择可能是在调用Ctx::new()
并将其作为参数传递之前初始化计时器子系统(和SDL),因为很难同时存储子系统和计时器(一个自引用结构体)。