Peter Popov
Peter Popov

Reputation: 662

Error returning reference to a temporary value when implementing a trait for a type reference

I am trying to implement a simple trait which returns a reference to some data (GetData). For different reasons, I need to implement this trait for reference to my type (&Base<T>). I also would like to have a wrapper type that owns the base type and implements the trait.

The simplified example looks like this:

    // Trait
    trait GetData<T> {
      fn get_data(&self) -> &T;
    }
    
    // Base type
    struct Base<T> {
      pub data: T,
    }
    
    impl<T> GetData<T> for &Base<T> {
      fn get_data(&self) -> &T {
        &self.data
      }
    }
    
    // Wrapper type owning a Base type
    struct Wrapper<T> {
      base: Base<T>,
      //...
    }
    
    impl<T> GetData<T> for &Wrapper<T> {
      fn get_data(&self) -> &T {
        (&self.base).get_data()  // E0515: returns a value referencing data owned by the current function 
        //&self.base.data        // This works fine!
      }
    }

When implementing get_data for a &Wrapper<T> I get an error of returning a temporary value from my function. As I understand &self.base is borrowed by GetData::get_data. I am not sure how to resolve it though. All my attempts to add explicit lifetimes didn't work so far.

Upvotes: 1

Views: 112

Answers (1)

Masklinn
Masklinn

Reputation: 42227

The issue is with this:

    impl<T> GetData<T> for &Base<T> {
      fn get_data(&self) -> &T {
        &self.data
      }
    }

Now in all honesty I've no idea why you'd bother implementing only for &Base instead of just implementing for Base. But that's the cause of the issue because the lifetime of the Base and the lifetime of the self are not the same and your self is an &&Base<T>.

This means in:

      fn get_data(&self) -> &T {
        (&self.base).get_data()  // E0515: returns a value referencing data owned by the current function 
        //&self.base.data        // This works fine!
      }

the lifetime of the result is that of &self.base which is purely local to the function, instead of being the expected lifetime of self.

If you

    impl<T> GetData<T> for Base<T> {
      fn get_data(&self) -> &T {
        &self.data
      }
    }

then everything works out of the box.

Can't help but think the entire thing smells of OO-thinking, a GetData trait stinks of Java/C# interface.

Upvotes: 2

Related Questions