I'd like to make the following code compile:
struct Provider {}
impl Provider {
fn get_string<'a>(&'a self) -> &'a str { "this is a string" }
}
fn main() {
let provider = Provider{};
let mut vec: Vec<&str> = Vec::new();
// PROBLEM: how do I say that this reference s here
// needs to live as long as vec?
let fun = |s: &str| {
vec.push(s);
};
fun(provider.get_string());
}
This is the compile error that I get:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:9:22
|
9 | let mut vec: Vec<&str> = Vec::new();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the block at 11:24...
--> src/main.rs:11:25
|
11| let fun = |s: &str| {
| ^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:12:18
|
12| vec.push(s);
| ^
note: but, the lifetime must be valid for the block suffix following statement 2 at 13:6...
--> src/main.rs:13:7
|
13| };
| ^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:11:9
|
11| let fun = |s: &str| {
| ^^^
Your code works just fine if remove all the lifetime annotations and let the compiler inference do its job:
In short, there's no way to explicitly refer to the lifetime of a local variable, only function arguments. The compiler knows how to do it, though.
If you truly needed it, you could create a function to allow annotating the lifetimes:
Specifically, it's this bit:
This declares a new lifetime on the closure. Using a made-up syntax (you can't declare lifetimes on closure arguments), it would be equivalent to:
Which is why the compiler has the error:
There's no connection between that generated lifetime and that of the
Provider
. Leaving it out allows the compiler to insert the desired but unnamable lifetime.Here's a version which compiles:
Playground link
I made the following changes:
Provider
(I added aPhantomData
, but I guess your provider already owns some data it'll provide).get_string
method to show that it returns something with the provider's lifetime, not the input lifetime (ie based on theProvider
's lifetime parameter).'b
to the function (which I renamed tof()
, sincemain()
can't have one), which I use to name the lifetime of the closure parameter.The last one is slightly confusing, as apparently merely adding a name to a lifetime (without apparently adding any constraints) has made it work.
I think (but I'd love some documentation for this) that this is because of lifetime elision. A closure is really a hidden
struct
with afn call(&self, s: &str)
(in this case) method. According to the lifetime elision rules, thes
parameter gains the same lifetime as&self
, which is the closure itself. In this case, the closure is declared aftervec
, so the lifetime is too short. The explicit lifetime means that it is decoupled from the closure's own lifetime.