Search code examples
rustlifetime-scoping

Mutable reference lives long enough when function is called directly, but doesn't live long enough when called through an intermediate function


For the following Rust code:

fn facing_of_mut<'a>(domain: &'a mut Domain, entity: Entity) -> Option<&'a mut Direction> {
    component_of_mut(&mut domain, entity)
}

...the compiler outputs:

error: `domain` does not live long enough
 --> src/facing.rs:5:27
  |
5 |     component_of_mut(&mut domain, entity)
  |                           ^^^^^^ does not live long enough
6 | }
  | - borrowed value only lives until here
  |
note: borrowed value must be valid for the lifetime 'a as defined on the body at 4:90...
 --> src/facing.rs:4:91
  |
4 |   fn facing_of_mut<'a>(domain: &'a mut Domain, entity: Entity) -> Option<&'a mut Direction> {
  |  ___________________________________________________________________________________________^ starting here...
5 | |     component_of_mut(&mut domain, entity)
6 | | }
  | |_^ ...ending here

I don't understand the error message because I thought the purpose of declaring those lifetimes was specifically to require that whatever object is passed as the domain parameter lives as long as the Direction reference in the return value that depends on the memory allocated by domain.

The signature of component_of_mut is:

pub fn component_of_mut<'a, C: 'static>(domain: &'a mut Domain, entity: Entity) -> Option<&'a mut C>

...and I can call it directly in unit tests without lifetime errors during compilation. It's only when facing_of_mut calls it that I get errors.


Solution

  • You are taking a reference to domain. domain is the local variable for the argument and is already a reference. domain only lasts for the duration of the function invocation, so that's how a long a reference to that value can exist.

    To fix it, don't try to take a reference to a reference:

    type Domain = String;
    type Entity = String;
    type Direction = String;
    
    pub fn component_of_mut<'a, C>(domain: &'a mut Domain, entity: Entity) -> Option<&'a mut C>
        where C: 'static
    {
        unimplemented!()
    }
    
    fn facing_of_mut<'a>(domain: &'a mut Domain, entity: Entity) -> Option<&'a mut Direction> {
        component_of_mut(domain, entity)
    }
    
    fn main() {}