Reputation: 3470
This code works fine:
#[derive(Debug)]
struct Foo<'a> {
data: Vec<&'a str>,
}
impl Foo<'_> {
fn bar_func(arg1: &str) {
let f = Foo { data : arg1.split_whitespace().collect() };
println!("{:?}", f.data);
}
}
fn main() {
Foo::bar_func(&"hey split me!");
}
But if I change Foo for Self when creating the struct:
fn bar_func(arg1: &str) {
let f = Self { data : arg1.split_whitespace().collect() };
println!("{:?}", f.data);
}
I get a lifetime error:
error: lifetime may not live long enough
--> src/main.rs:9:31
|
6 | impl Foo<'_> {
| -- lifetime `'2` appears in the `impl`'s self type
7 |
8 | fn bar_func(arg1: &str) {
| - let's call the lifetime of this reference `'1`
9 | let f = Self { data : arg1.split_whitespace().collect() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
|
= note: requirement occurs because of the type `SplitWhitespace<'_>`, which makes the generic argument `'_` invariant
= note: the struct `SplitWhitespace<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Until now I assumed that these would be interchangeable, and I tend to use Self most of the time, so you can imagine, this got me stuck for a very long time, and it was just luck how I found that it worked fine with the struct name when trying to isolate the problem in a minimal example.
Are they not equivalent, and if so, what is the difference?
Upvotes: 0
Views: 51
Reputation: 70940
They're not the same.
Foo
is Foo<'_>
, with inferred (or elided) lifetime, and that means we can use the lifetime of arg1
.
Self
, however, keeps generic parameters of the current type, and that includes lifetimes. Thus, the lifetime of Foo
with Self
refer to the elided '_
in impl Foo<'_>
, which is a distinct generic lifetime that is incompatible with arg1
's lifetime.
Upvotes: 1