Search code examples
rustmutabledereference

Returning mutable reference of trait in vector


New to rust, I'm trying to build a state stack.

pub trait State {
    fn tick(&mut self);
}

pub struct StateStack {
    stack: Vec<Box<dyn State>>,
}

impl StateStack {
    pub fn push(&mut self, state: Box<dyn State>) {
        self.stack.push(state);
    }

    pub fn current(&mut self) -> &mut dyn State
    {
        &**self.stack.last_mut().expect("No state in stack")
    }
}

When compiling, I get this error:

error[E0308]: mismatched types
  --> src/main.rs:16:9
   |
14 |     pub fn current(&mut self) -> &mut dyn State
   |                                  -------------- expected `&mut dyn State` because of return type
15 |     {
16 |         &**self.stack.last_mut().expect("No state in stack")
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
   |
   = note: expected mutable reference `&mut dyn State`
                      found reference `&(dyn State + 'static)`

I don't understand where this State + 'static' come from, is this even the issue ? I'm not sure where to begin to analyze this error. I think I get the deref chain right, but I feel I might be missing something here.

As a side question, I'm an OOP developper, and I'm not sure that what I'm doing is going the rustly way. Any other architecture to considere for state stack ?


Solution

  • The issue is you downgrade the mutable reference you got with last_mut to an immutable reference when you use &**. You need to instead take a mutable reference and that will solve the issue:

     &mut **self.stack.last_mut().expect("No state in stack")
    

    As for &(dyn State + 'static'), you can mostly just ignore the 'static. Anonymous traits (dyn Trait) are not concrete types so they may not all share the same lifetime requirements. dyn State + 'static indicates an anonymous State trait which can survive for a lifetime of 'static. 'static just means that a lifetime in unconstrained and could be placed in a static context. Most types have a lifetime of 'static so it does not get included in regular use. Some types with 'static lifetimes would be primitives like u32 or f64. Any dyn Trait which does not include a lifetime gets an implicit 'static.