Lifetime: How to return object with lifetime


#1

Another day another question :smiley:

pub struct Stuff;

pub struct Example<'c> {
    data: Vec<&'c Stuff>
}

impl<'c> Example<'c> {
    pub fn new() -> &'c Self {
       &Example {
            data: vec![]
        }
    }
}

fn main() {
    let e = Example::new();
}

This code gives me the error:

main.rs:9:9: 11:10 error: borrowed value does not live long enough
main.rs: 9        &Example {
main.rs:10             data: vec![]
main.rs:11         }

This is totally clear. But how am I able to return a reference?


#2

Alternatively solution could be not using references but initiate lifetime objects like this:

struct Stuff<'c> {
    name: &'c str
}

impl<'c> Stuff<'c> {
    pub fn new() -> Self {
        Stuff {
            name: "blubb"
        }
    }
}

pub struct Example<'c> {
    data: Vec<&'c Stuff<'c>>
}

impl<'c> Example<'c> {
    pub fn new() -> Self {
        let s = Stuff::new();
        Example {
            data: vec![&s]
        }
    }
}

fn main() {
    let e = Example::new();
}

But it is also not working as I understood till now.


#3

That’s why we’re here! :smile:

[quote]
But how am I able to return a reference?[/quote]

The issue is here:

   pub fn new() -> &'c Self {
       &Example {
            data: vec![]
        }
    }

Let me write it without the temporary, in hopes of bringing some clarity:

   pub fn new() -> &'c Self {
       let example = Example {
            data: vec![]
        }

        return &example;
    } // example goes out of scope here

The problem is that at the end of your function, example is going to go out of scope, and so, be deallocated. Return by value instead:

   pub fn new() -> Self {
       Example {
            data: vec![]
        }
    } 

#4

This heavily depends on what you intend to do.
You might wanna:

struct<'a, T> Foo {
  data: &'a [T]
}

impl Foo {
  fn new<'a, T>(other: &'a [T]) -> Foo<'a, T> { Foo { data: other} }
}

This returns Foo by value, but it contains reference, and so cannot outlive its internals.
Hope this helps.

EDIT: I reviewed your second comment more closely.
In Rust, references don’t pin value in memory and don’t prolong its lifetime. There’s no garbage collection. So you cannot create some value inside a function and then let reference to it escape - because when you leave function value would be destroyed, and your reference will point to some garbage. That’s one of many problems Rust solves with lifetimes and borrowed references.


#5

Okay. Thank you for your input.

Maybe a more real world example: https://gist.github.com/dweidenfeld/20662812b55c79ae4d50
Please be aware that the - represents a / in the filenames :wink:

I’ve annotated my problem in JobController. D seems not to live long enough, but I don’t know how to let it live longer… or the right time.


#6

Okay I was totally wrong. Now I found the solution myself.
Thank you for the support, without it it would not have been possible for me to solve the problem :smile:

I won’t release the gist, but will later push a complete git repo with the final solution (takes some time ;))