I have been pulling my hair on this one for quite some time now ; and it made me realize that no, I still don't grok lifetimes. The following code is a simplified version of my actual problem, but the errors I am getting are the same.
Let's say I have a trait for anything that can provide a buffer:
trait BufferProvider<'a> {
type BufferType: 'a;
fn get_buffer(&'a self) -> Self::BufferType;
}
Buffers returned by implementors of this trait shall not outlive the object that provided them, which I think is correctly expressed by the 'a
lifetime: anything returned by get_buffer()
cannot outlive self
.
Let's implement this trait:
struct Pool {
}
struct Buffer<'a> {
_pool: &'a Pool,
}
impl<'a> BufferProvider<'a> for Pool {
type BufferType = Buffer<'a>;
fn get_buffer(&'a self) -> Buffer<'a> {
Buffer { _pool: self }
}
}
Buffer
s hold a (dummy for this example) reference to the Pool
that provided them and thus shall not outlive it ; the trait looks easy to implement in this case.
Now I want a struct that will make use of a BufferProvider
from a few methods:
struct BufferUser<'a, BP>
where BP: BufferProvider<'a>,
{
provider: BP,
_l: PhantomData<&'a BP>,
}
Since 'a
is required to mention BufferProvider
, I need to use a PhantonData
otherwise that declaration won't compile.
And now the real fun:
impl<'a, BP> BufferUser<'a, BP>
where BP: BufferProvider<'a>,
{
fn do_something(&'a self) {
let buffer = self.provider.get_buffer();
// do something with the buffer...
drop(buffer);
}
fn run(self) {
self.do_something();
}
}
First let's look at do_something()
. It gets a buffer from the provider, and drops it after a while. There is no way the buffer outlives self
or self.provider
. Yet, unless I specify the lifetime 'a
for self, I get the following error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:36:36
|
36 | let buffer = self.provider.get_buffer();
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 35:5...
--> src/main.rs:35:5
|
35 | fn do_something(&self) {
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:36:22
|
36 | let buffer = self.provider.get_buffer();
| ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 31:6...
--> src/main.rs:31:6
|
31 | impl<'a, BP> BufferUser<'a, BP>
| ^^
note: ...so that the types are compatible
--> src/main.rs:36:36
|
36 | let buffer = self.provider.get_buffer();
| ^^^^^^^^^^
= note: expected `&'a BP`
found `&BP`
In a way that makes sense ; we need to restrict 'a
to self
, and after that this method compiles.
But then, run()
is unhappy:
error[E0597]: `self` does not live long enough
--> src/main.rs:42:9
|
31 | impl<'a, BP> BufferUser<'a, BP>
| -- lifetime `'a` defined here
...
42 | self.do_something();
| ^^^^---------------
| |
| borrowed value does not live long enough
| argument requires that `self` is borrowed for `'a`
43 | }
| - `self` dropped here while still borrowed
This one confuses me beyond words. How can do_something()
, which does not return anything, borrow self
for longer than the duration of run()
? My understanding of the 'a
lifetime is that 'a
represents the lifetime of self within do_something()
, since that's the only place where it is used in the impl
block. But from this message it seems like I am in fact completely missing the mark.
Could someone explain me what is going on in this code? Also, how can I make it work? I have posted a playground populated with the code in this example for those kind enough to try and solve this.