There is some minimal example library code I would like to use:
struct MyR<'a> {
x: &'a str,
}
struct T {
x: &'static str,
}
impl T {
fn bar<'a>(&'a self) -> MyR {
MyR { x: self.x }
}
}
The following is my code:
trait A<R, F: FnMut(&R)> {
fn foo(&mut self, callback: &mut F);
}
impl<'a, F> A<MyR<'a>, F> for T
where F: FnMut(&MyR<'a>)
{
fn foo(&mut self, callback: &mut F) {
let t = T { x: "l" };
let r = t.bar(); // t does not live long enough (for 'a)
callback(&r);
println!("abc");
}
}
fn test() {
let mut t = T { x: "l" };
let mut i = 1;
t.foo(&mut |x| { i += x.x.len(); });
}
I would like to make a trait that is parametrized by the callback, but I struggled to make it right. If I don't use a trait, it works well:
impl T {
fn foo<F: FnMut(&MyR)>(&mut self, callback: &'a mut F) {
let t = T { x: "l" };
let r = t.bar();
callback(&r);
println!("abc");
}
}
But I cannot do this:
impl T {
fn foo<'a, F: FnMut(&MyR<'a>)>(&mut self, callback: &mut F) {
let t = T { x: "l" };
let r = t.bar();
callback(&r);
println!("abc");
}
}
I know the problem is that t
must outlive 'a
, but I don't know to bound 'a
so that its lifetime is shorter than t
.
I'm using rustc 1.19.0-nightly.
Read the error messages:
t
does not live long enough — it lives until the end of thefoo
function.borrowed value must be valid for the lifetime 'a — you have specified
'a
:This says that for any possible lifetime, the trait will be implemented, so long as
F
implements theFnMut
trait.There's only one possible way to make that work — you have to have a
MyR
that is parameterized with the'static
lifetime. That's the only lifetime that is guaranteed to outlive any arbitrary lifetime.Let's see where
MyR
comes from:If you go back and reread The Rust Programming Language section on lifetime elision, you'll recognize that this lifetime specification provides no value. It defines a lifetime and uses it with
self
, but it's never tied to any output lifetimes. The code is the same as:If you removed the lifetime, then you'd have
However, neither of these is the
'static
lifetime. Luckily for you, you know that thatx
is a&'static str
, so you can just reflect that in your signature and the code will compile:Spending hours trying different approaches, this seems to work
The main difference is:
Playground