Lifetime of references created in a generic function

Hi all,

I need to write a generic function which instantiates a value of a given type and passes it a reference. Thus the trait which the given type needs to implement is parametrized with a lifetime. I would like to achieve something like in case 1, so the type is passed before the reference I want exists. If I create that value before (case 2) all works well. For the completeness reason I also added case 3 but it doesn't compile as well. I read the answer here [1] , but I couldn't apply it to my case.

Thanks in advance,
--alan

trait Fooer<'a> {
    fn new(r: &'a i32) -> Self;
    fn foo(&self) -> ();
}

struct AFooer<'a> {
    r: &'a i32,
}

impl<'a> Fooer<'a> for AFooer<'a> {
    fn new(r: &'a i32) -> Self {
        AFooer { r }
    }
    fn foo(&self) -> () {
        println!("AFooer: {}", *self.r);
    }
}

fn make_fooer<T: for<'a> Fooer<'a>>() {
    let x: i32 = 42;
    let fooer = T::new(&x);
    fooer.foo();
}

fn make_fooer2<T: for<'a>Fooer<'a>>() {
    let x: i32 = 42;
    make_fooer_internal::<T>(&x);
}

fn make_fooer_internal<'a, T: Fooer<'a>>(x: &'a i32) {
    let fooer = T::new(&x);
    fooer.foo();
}

fn main() {
    //1
    //make_fooer::<AFooer>(); - this doesn't compile

    //2
    let x: i32 = 42;
    make_fooer_internal::<AFooer>(&x);

    //3
    //make_fooer2::<AFooer>(); - this doesn't compile
}

[1] https://stackoverflow.com/questions/50946525/why-do-the-lifetimes-on-a-trait-object-passed-as-an-argument-require-higher-rank

1 Like

When you look at the error message:

the trait bound `for<'a> AFooer<'_>: Fooer<'a>` is not satisfied

It becomes clear that the type T gets a lifetime elided in the main function while we want the 'a in the make_fooer function. I don't know any way to do this, so instead I'll consider it a limitation of the compiler and propose an alternative.

You seem to be trying to do a strategy pattern so why not simplify it to this:

trait Fooer {
    fn foo(r: &i32);
}

struct AFooer<'a> {
    r: &'a i32,
}

impl<'a> Fooer for AFooer<'a> {
    fn foo(r: &i32) -> () {
        //alternatively create a AFooer object here
        println!("AFooer: {}", r);
    }
}

fn make_fooer<T: Fooer>() {
    let x: i32 = 42;
    T::foo(&x); //EDIT
}

fn main() {
    make_fooer::<AFooer>();
}

This solve the problem in your example, but does this also solve it in your actual code?

1 Like

Hi, thanks for the reply.

Unfortunately the solution you sent doesn't solve the issue I have because the function make_fooer shouldn't mention concrete type (AFooer) but should use the type parameter. The whole idea is that I would have more than one implementer of the trait.

Whoops, I made make_fooer, but used the concrete type instead the type parameter T. I changed it in my original reply.