Reputation: 3169
How do I resolve this error? What exactly am I telling the compiler when I use the "anonymous lifetime" in impl
?
struct LineHandlerInfo<'a> {
label: &'a str,
match_literal: &'a str,
f: fn(&str) -> Option<&str>,
}
struct Game<'a> {
handlers: Vec<LineHandlerInfo<'a>>,
}
impl Game<'_> {
fn match_str<'a>(
&'a mut self,
label: &'a str,
match_literal: &'a str,
mut f: fn(&str) -> Option<&str>,
) {
let mut lh = LineHandlerInfo {
label,
match_literal,
f,
};
self.handlers.push(lh);
}
}
fn main() {
let mut g = Game {
handlers: Vec::new(),
};
g.match_str("echo hello", "hello", |s| {
println!("{}", s);
None
});
}
When I attempt to compile, I get the following error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:18:22
|
18 | let mut lh = LineHandlerInfo {
| ^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the method body at 12:18...
--> src/main.rs:12:18
|
12 | fn match_str<'a>(
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:19:13
|
19 | label,
| ^^^^^
note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 11:11...
--> src/main.rs:11:11
|
11 | impl Game<'_> {
| ^^
= note: ...so that the expression is assignable:
expected LineHandlerInfo<'_>
found LineHandlerInfo<'_>
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game
when I already have a lifetime on the struct?
Upvotes: 3
Views: 3273
Reputation: 30587
How do I resolve this error and what exactly am I telling the compiler when I specify a lifetime on impl Game when I already have a lifetime on the struct?
I suspect your confusion stems from an incomplete understanding of the way in which lifetimes are declared and used in Rust.
In order to use a lifetime on a struct, you declare the lifetime inside the <>
adjacent to the name of the struct you are declaring, and then refer to that lifetime inside the struct definition. Importantly, note that the lifetime declared there is scoped to the struct definition - it has no meaning outside.
For example (using the MRE that @Shepmaster provided):
struct Game<'a> {
handlers: Vec<&'a str>,
}
The struct Game
contains a vector of references to strings, and the strings which are referenced must last at least as long as the Game
struct.
When using a lifetime specifier on an impl block, you declare the lifetime inside the <>
adjacent to the impl keyword, after which you may refer to the lifetime both in the struct being implemented, and inside the implementation itself, like this:
impl<'b> Game<'b> {
fn match_str(&mut self, label: &'b str) {
self.handlers.push(label);
}
}
Note that I am using an entirely different lifetime name here ('b
) to illustrate that the the lifetime declaration on the struct is independent of the one on the impl block.
Breaking this down:
impl<'b>
This means that we are defining an implementation for a struct, and within that definition we will use the lifetime 'b
Game<'b> {
This means that the impl is for the struct Game
with lifetime 'b
- so any references to self
inside this implementation are going to automatically have lifetime 'b
as well.
fn match_str(&mut self, label: &'b str) {
Here we define the method match_str
which takes an argument label
. label
is a string slice which also has the lifetime 'b
- so it must last at least as long as the self
that the method is called on.
In your original code, you had something like this:
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
...
}
}
This was telling the compiler:
Game
; this struct has a lifetime parameter but we don't care about it and we are not going to tie it to any element of the implementationmatch_str
, and we are declaring a lifetime 'a
which we can refer to in the rest of the function signaturelabel
which has the lifetime a
, but we aren't relating this lifetime to anything elseMore information:
Upvotes: 15
Reputation: 430851
How do I resolve this error?
Remove the generic lifetime from the function, provide a name for the lifetime on the impl
block instead of using the anonymous lifetime, then use the named lifetime in the function arguments. Remove the lifetime from &self
:
impl<'a> Game<'a> {
fn match_str(&mut self, label: &'a str, match_literal: &'a str, f: fn(&str) -> Option<&str>) {
self.handlers.push(LineHandlerInfo {
label,
match_literal,
f,
});
}
}
See also:
What exactly am I doing when I use the "anonymous lifetime" in impl?
You are effectively stating "I know there's a lifetime here, but I don't care about it". However, that's not true for your case; you do care about the lifetime that parameterizes the type because that's what your variables need to match.
See also:
'_
, the anonymous lifetime in the Edition Guidefor a struct with a function pointer in it
This has nothing to do with function pointers. When encountering problems while programing, I recommend creating a minimal, reproducible example, stripping out things that don't make the error go away. This allows you to focus on exactly the problem at hand. For example, this reproduces the same error:
struct Game<'a> {
handlers: Vec<&'a str>,
}
impl Game<'_> {
fn match_str<'a>(&mut self, label: &'a str) {
self.handlers.push(label);
}
}
Upvotes: 1