Can't figure out borrowing/lifetime problem

I have tried every permutation of cloning, referencing, dereferencing that I can think of, but I cannot get past this lifetime problem. If I change line 18 to let bar = &self.foo it works. Why is that lifetime any different than the function I wrote to do the same thing? What am I missing?

extern crate itertools; // 0.7.8
use itertools::Itertools;

fn main() {
    let f = Foo { foo: vec![1,3,3,1,6] };
    let groups = f.grouping();
    println!("{:?}", groups)
}

struct Foo {
    foo: Vec<u8>
}

impl Foo {
    fn grouping(&self) -> Vec<Vec<&u8>> {
        let bar = &self.foo();

        let iter = bar.iter();
        let groups = iter.group_by(|x| *x)
                     .into_iter()
                     .map(|(_,a)| a.into_iter().collect::<Vec<&u8>>())
                     .collect::<Vec<Vec<&u8>>>();
                     groups
    }

   fn foo(&self) -> Vec<u8> {
       self.foo
  }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (file:///playground)
error[E0597]: borrowed value does not live long enough
  --> src/main.rs:18:16
   |
18 |     let bar = &self.foo();
   |                ^^^^^^^^^^ temporary value does not live long enough
...
26 | }
   | - temporary value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 17:1...
  --> src/main.rs:17:1
   |
17 | / fn grouping(&self) -> Vec<Vec<&u8>> {
18 | |     let bar = &self.foo();
19 | |
20 | |     let iter = bar.iter();
...  |
25 | |                      groups
26 | | }
   | |_^

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:29:5
   |
29 |     self.foo
   |     ^^^^ cannot move out of borrowed content

error: aborting due to 2 previous errors

Some errors occurred: E0507, E0597.
For more information about an error, try `rustc --explain E0507`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

In grouping, you’re saying that you’re going to return a reference to data that is contained in self:

fn grouping(&self) -> Vec<Vec<&u8>>
            ^                 ^
            references implicitly have the same lifetime

However, your function foo does not return a reference:

fn foo(&self) -> Vec<u8>
       ^         ^
       |         owned value
       reference

So when you write:

let bar = &self.foo();

The return value of foo() is stored locally on the stack and you’re taking a reference to that. You can’t return a reference to a variable on your local stack, as the variable will be deallocated when your function returns. Or, looking at it another way, in your function signature (above), you promised to return data that was contained in self, which is not the case for local stack variables.

You can change your function foo to return a reference as well:

fn foo(&self) -> &Vec<u8> {
    &self.foo
}

Now that’s actually doing the same thing as just writing let bar = &self.foo;, and it works fine that way.

1 Like

Thank you, that makes sense. But what if I want to do something other than just return the field value? For instance if the struct is

struct Foo {
   foo: Vec<u8>,
   bar: Vec<u8>
}

and the function is

fn foo(&self) -> Vec<u8> {
    let mut buf = vec![];
   buf.extend(self.foo);
   buf.extend(self.bar);
  buf
}

there’s a lifetime issue even if you clone the values first.

You just need to borrow the fields for the extend calls:

buf.extend(&self.foo);
buf.extend(&self.bar);