Creating object with reference creates error when using Self

I have two functions doing the same thing, but only one compiles without error:

struct Something<'number> {
    numbers: &'number [i64]
}

impl<'number> Something<'number> {
    fn hasna() {
        let dummy = [0, 1, 2, 3];
        let s = Self {numbers: &dummy[1..3]};
    }
    fn bruzzn() {
        let dummy = [0, 1, 2, 3];
        let s = Something {numbers: &dummy[1..3]};
    }
}

fn bruzzn does compile, but hasna doesn't - with the error

77 | impl<'number> Something<'number> {
   |      ------- lifetime `'number` defined here
78 |     fn hasna() {
79 |         let dummy = [0, 1, 2, 3];
   |             ----- binding `dummy` declared here
80 |         let s = Self {numbers: &dummy[1..3]};
   |                                -^^^^^------
   |                                ||
   |                                |borrowed value does not live long enough
   |                                this usage requires that `dummy` is borrowed for `'number`
81 |     }
   |     - `dummy` dropped here while still borrowed

Why is using Self a problem when using the struct name works?

There are two facts you need to understand this.

First, a local variable necessarily does not outlive a lifetime that is a parameter to the function. In this case: it is always impossible to create an &'number [i64] that points to dummy.

Second, Self is an alias for exactly the type given in the impl. In this case, Self is an alias for Something<'number>. So, if we replace Self with Something<'number>, and notice the lifetime in the other function, we get:

    fn hasna() {
        let dummy = [0, 1, 2, 3];
        let s = Something<'number> {numbers: &dummy[1..3]};
    }
    fn bruzzn() {
        let dummy = [0, 1, 2, 3];
        let s = Something::<'_> {numbers: &dummy[1..3]};
    }

bruzzn compiles because it creates a Something<'1>, where '1 is the unnamed lifetime of a borrow of the local variable dummy, which contains a reference &'1 [i64].

hasna does not compile because it is trying to create a Something<'number>, which must contain a reference &'number [i64], which cannot be obtained by borrowing the local variable dummy.

bruzzn has a lifetime parameter number — its full name is Something::<'number>::bruzzn — but it does not actually make any use of that lifetime parameter, because it never mentions it in any way, not even via Self.

Thanks a lot - weirdly enough I understand it... but my mental model for lifetimes for sure is still incomplete.

btw. it's Something::<'_> :slight_smile:

I think almost everybody’s mental model of lifetimes is not really complete. There’s a lot of subtleties (mostly to do with local variables, not named lifetimes).