TL; DR
嵌套对象的生存期存在问题。代码如下。
长版:
我正在使用ggez
编写多人游戏,并且试图为输入创建一个抽象层(以允许本地和远程玩家一起玩)。
为了做到这一点,我创建了一个Input
特性,并为本地输入实现了KeyboardInput
,它使用ggez
键盘状态查询方法。
现在最棘手的部分:ggez
在启动时创建Context
对象,并期望在大多数公开的函数中对其进行引用。
因为我的KeyboardInput
实现使用的是ggez
输入法(特别是is_key_pressed
),所以必须将&Context
传递给此方法。但是,由于特征本身应该是通用的,因此任何其他实现(例如Context
)都不需要NetworkInput
引用。
我的解决方案是在Context
结构中添加对KeyboardInput
的引用作为字段。但是,这导致了我仍然无法解决的终身错误。
我还尝试将生命周期设置为'static
,但这也不起作用。
这是相关的代码:
pub trait Input {
fn get_direction(&self) -> Direction;
}
pub struct KeyboardInput<'a> {
left_key: KeyCode,
right_key: KeyCode,
_ctx: &'a Context
}
impl KeyboardInput<'_> {
pub fn new(_ctx: &Context, left_key: KeyCode, right_key: KeyCode) -> KeyboardInput {
KeyboardInput{
_ctx,
left_key,
right_key
}
}
}
impl Input for KeyboardInput<'_> {
fn get_direction(&self) -> Direction {
if ggez::input::keyboard::is_key_pressed(self._ctx, self.left_key) {
return Direction::Left;
}
if ggez::input::keyboard::is_key_pressed(self._ctx, self.right_key) {
return Direction::Right;
}
Direction::Unchanged
}
}
struct Player {
angle: f32,
pos_x: f32,
pos_y: f32,
input_manager: Box<dyn Input>,
}
impl <'a>MainState {
fn new(ctx: &'a Context) -> GameResult<MainState> {
let kbd_input = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
let kbd_input = Box::new(kbd_input);
let s = MainState {
last_update: Instant::now(),
players: vec![
Player::new(kbd_input)
]
};
Ok(s)
}
}
pub fn main() -> GameResult {
let cb = ggez::ContextBuilder::new("My game", "ggez");
let (ctx, event_loop) = &mut cb.build()?;
let state = &mut MainState::new(&ctx)?;
event::run(ctx, event_loop, state)
}
和编译器错误:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src\main.rs:75:25
|
75 | let kbd_input = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 72:7...
--> src\main.rs:72:7
|
72 | impl <'a>MainState {
| ^^
note: ...so that reference does not outlive borrowed content
--> src\main.rs:75:44
|
75 | let kbd_input = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
| ^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn input_manager::Input + 'static)>
found std::boxed::Box<dyn input_manager::Input>
最佳答案
该错误几乎总是意味着您试图以一种比其生命周期更长的时间存储值。
让我们看一段特定的代码,这些代码带有显式的类型和生存期:
impl<'a> MainState {
fn new(ctx: &'a Context) -> GameResult<MainState> {
let kbd_input: KeyboardInput<'a> = KeyboardInput::new(ctx, KeyCode::Left, KeyCode::Right);
let kbd_input: Box<dyn Input + 'a> = Box::new(kbd_input);
let s: MainState = MainState {
last_update: Instant::now(),
players: vec![
Player::new(kbd_input as Box<dyn Input + 'static>)
]
};
Ok(s)
}
}
在第9行上,您尝试将
kbd_input
分配给Box<dyn Input>
。但是Box<dyn Input>
没有明确的生存期,它隐式等效于Box<dyn Input + 'static>
。因此,您试图将带有生存期'a
的值分配给具有静态生存期的类型,这是不允许的。解决方案是显式设置特征对象类型的生存期:
Box<dyn Input + 'a>
。这是级联的,这意味着您还需要向MainState
结构添加生命周期,因为它现在将包含具有非静态生命周期的类型:struct MainState<'a> {
/* ... */
players: Vec<Box<dyn Input + 'a>>,
}
关于rust - 无法定义适当的防 rust 生命周期要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59491563/