Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Traits with GAT as a method generic argument: "borrowed value does not live long enough"

I’m trying to write a function that takes a generic argument over a trait with a GAT.

Here is my code (playground):

struct Owned;

struct Ref<'a> {
    owned: &'a Owned,
}

trait Abstract {
    type Input<'a>;
    fn method(&self, _input: &Self::Input<'_>);
}

struct Concrete;

impl Abstract for Concrete {
    type Input<'a> = Ref<'a>;
    fn method(&self, _input: &Self::Input<'_>) {}
}

fn act<'a, A>(abs: A) where A: Abstract<Input<'a> = Ref<'a>> {
    let owned = Owned {};
    let obj_ref = Ref { owned: &owned } ;
    abs.method(&obj_ref);
}

// This works, but I'd prefer building the owned value inside the function.
// fn act2<'a, A>(abs: A, owned: &'a Owned) where A: Abstract<Input<'a> = Ref<'a>> {
//     let obj_ref = Ref { owned } ;
//     abs.method(&obj_ref);
// }

I’m trying to get the method act to work. The error I’m getting:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

   Compiling playground v0.0.1 (/playground)
error[E0597]: `owned` does not live long enough
  --> src/main.rs:21:32
   |
19 | fn act<'a, A>(abs: A) where A: Abstract<Input<'a> = Ref<'a>> {
   |        -- lifetime `'a` defined here
20 |     let owned = Owned {};
21 |     let obj_ref = Ref { owned: &owned } ;
   |                                ^^^^^^ borrowed value does not live long enough
22 |     abs.method(&obj_ref);
   |     -------------------- argument requires that `owned` is borrowed for `'a`
23 | }
   | - `owned` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error

I understand the problem and why it doesn’t work, but I’m unsure how to fix it. I found a workaround with the method act2, which is a reasonable solution, but that forces me to create the Owned object outside of the method, which is not what I’m looking for.

>Solution :

It’s impossible to have a reference to a thing that’s owned by the current function owned in act live as long as the caller wants it to 'a because it gets dropped at the end of the function } in line 23. In the end the Owned struct has to be stored somewhere.

But if Owned is a literal you can exploit static promotion like this:

fn act<'a, A>(abs: A) where A: Abstract<Input<'a> = Ref<'a>> {
    let obj_ref = Ref { owned: &Owned } ;
    abs.method(&obj_ref);
}

You can also not let the caller of act determine the lifetime by using HRTBs instead of a generic lifetime:

fn act<A>(abs: A) where for<'a> A: Abstract<Input<'a> = Ref<'a>> {
    let owned = Owned;
    let obj_ref = Ref { owned: &owned } ;
    abs.method(&obj_ref);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading