Extending reference to that of owning struct

In the below code the last statement in the main function complains that the borrowing struct is dropped, however it seems like it should be possible to return the reference to the value as it is actually from the owned value which lives long enough.

Maybe there is an unhelpful elided lifetime but I can't seem to work out something that does what I'd want.

Does anyone have a solution for this?

type Value = u32;

struct Ret<'a>(&'a Value);

struct Owning {
    value: Value,
}

struct Borrowing<'a> {
    owned: &'a Owning,
}

trait Get {
    fn get(&self) -> Ret;
}

impl Get for Owning {
    fn get(&self) -> Ret {
        Ret(&self.value)
    }
}

impl<'a> Get for Borrowing<'a> {
    fn get(&self) -> Ret<'a> {
        self.owned.get()
    }
}

fn main() {
    let owning = Owning { value: 2 };
    let value_from_owned = owning.get();
    println!("{:?}", value_from_owned.0);

    let owned_ref = &owning;
    let value_from_owned_ref = owned_ref.get();
    println!("{:?}", value_from_owned_ref.0);
    
    let borrowed = Borrowing { owned: owned_ref};
    let value_from_borrowed = borrowed.get();
    println!("{:?}", value_from_borrowed.0);
    
    let value_from_borrowed = Borrowing { owned: owned_ref }.get();
    println!("{:?}", value_from_borrowed.0);
}

(Playground)

Indeed: your definition of Get, unelided, is:

trait Get {
    fn get<'x>(&'x self) -> Ret<'x>;
}

Thus, the caller only knows that the Ret is valid as a borrow of self, not as anything longer-lived. I recommend setting the lint configuration #![deny(elided_lifetimes_in_paths)] (which will require you to write Ret<'a> or Ret<'_>) to avoid having this type of issue without noticing.

Does anyone have a solution for this?

You can implement the trait on references so that it has access to the reference lifetime but isn't obligated to use it:

trait Get<'a> {
    fn get(self) -> Ret<'a>;
}

impl<'a> Get<'a> for &'a Owning {
    fn get(self) -> Ret<'a> {
        Ret(&self.value)
    }
}

impl<'a> Get<'a> for &Borrowing<'a> {
    fn get(self) -> Ret<'a> {
        self.owned.get()
    }
}
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.