【问题标题】:Cannot define appropriate rust lifetime requirements无法定义适当的生锈寿命要求
【发布时间】:2019-12-26 17:30:39
【问题描述】:

TL;DR 嵌套对象的生命周期存在问题。代码如下。

加长版:

我正在使用ggez 编写多人游戏,并且我正在尝试为输入创建一个抽象层(以允许本地和远程玩家一起玩)。

为此,我创建了一个Input trait,并为本地输入实现了KeyboardInput,它使用ggez 键盘状态查询方法。

现在棘手的部分是:ggez 在启动时创建 Context 对象,并期望在大多数公开的函数中引用它。

因为我的KeyboardInput 实现是使用ggez 输入法(特别是is_key_pressed),所以它必须将&Context 传递给这个方法。但是,由于 trait 本身应该是通用的,因此任何其他实现都不需要 Context 引用(例如,NetworkInput)。

我的解决方案是在KeyboardInput 结构中添加对Context 的引用作为字段。但是,这导致了我仍然无法解决的终身错误。

我也尝试过使用'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>

【问题讨论】:

    标签: rust traits lifetime


    【解决方案1】:

    这个错误几乎总是意味着你试图以一种可以比它的生命周期更长的方式存储一个值。

    让我们看一段特定的代码,带有显式类型和生命周期的注释:

    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&lt;dyn Input&gt;。但是Box&lt;dyn Input&gt; 没有显式的生命周期,它隐式地等价于Box&lt;dyn Input + 'static&gt;。因此,您尝试将具有生命周期 'a 的值分配给具有静态生命周期的类型,这是不允许的。

    解决方案是显式设置特征对象类型的生命周期:Box&lt;dyn Input + 'a&gt;。这级联意味着您还需要为 MainState 结构添加生命周期,因为它现在将包含具有非静态生命周期的类型:

    struct MainState<'a> {
      /* ... */
      players: Vec<Box<dyn Input + 'a>>,
    }
    

    【讨论】:

      猜你喜欢
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-25
      相关资源
      最近更新 更多