palako
palako

Reputation: 3470

What difference between Self and the struct name produces this error?

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

Answers (1)

Chayim Friedman
Chayim Friedman

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

Related Questions