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:
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);
}