4
votes

Consider the following example

trait MyTrait<'a> {
    type N: 'a;

    fn func(&'a self) -> Self::N;
}

fn myfunc<'a, T: 'a + MyTrait<'a>>(g: T) {
    g.func();
}

fn main() {}

Compiling this small program fails with:

error[E0597]: `g` does not live long enough
 --> src/main.rs:8:5
  |
8 |     g.func();
  |     ^ borrowed value does not live long enough
9 | }
  | - borrowed value only lives until here
  |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 7:1...
 --> src/main.rs:7:1
  |
7 | fn myfunc<'a, T: 'a + MyTrait<'a>>(g: T) {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

As far as I understand, the lifetime parameter 'a is not restricted and could be arbitrary. However, g is a parameter and its lifetime is only the function scope, therefore it does not satisfy the condition of lifetime 'a in the definition of method func.

What I really want is that the associated type N is always restricted to the lifetime of self in MyTrait. That's why I came up with the explicit lifetime parameter 'a of MyTrait. I want function myfunc to work, i.e. 'a should somehow be restricted to the lifetime of of the parameter g.

What is the "correct" way to solve this problem?

A very simple example is

struct MyPtr<'a> {
    x: &'a usize,
}

struct MyStruct {
    data: Vec<usize>,
}

impl<'a> MyTrait<'a> for MyStruct {
    type N = MyPtr<'a>;

    fn func(&'a self) -> Self::N {
        MyPtr { x: &self.data[0] }
    }
}

Note that this is extremely simplified, of course. The idea is that N always contains a reference to something contained in MyTrait and should therefore never outlive MyTrait.

1
Why do you want to constrain N to the lifetime of self? Could you show us an example implementation of MyTrait? Maybe you just need to change &'a self to &self.Francis Gagné
“What I really want is that the associated type N is always restricted to the lifetime of self.” I’d like to point out that the : in the context of lifetimes means “outlives”, not the other way around. So N: 'a does not really restrict N, it just says that it lives at least as long as self, which should be true anyway for the struct type to be well-formed.kirelagin
Nevertheless, you still might need to put it down explicitly, e.g. for your example to work. I just wanted to make it clear, that this “restriction” works the other way around, you do not restrict it to the lifetime of self, you demand that it lives longer than self.kirelagin

1 Answers

3
votes

What you want is not to bind a generic lifetime, but to allow "any" lifetime:

fn myfunc<T: for<'a> MyTrait<'a>>(g: T) {
    g.func();
}

Fully working example in the playground.

The best source for an explanation is How does for<> syntax differ from a regular lifetime bound?.