How to return a object created into a function?

Hello,
I am trying to build a web application with diesel and rocket and I have this function :

    pub fn get(id: i32, conn: &PgConnection) -> Option<&Task> {
        let tasks = all_tasks.find(id).load::<Task>(conn).expect("Error loading task");
        if tasks.len() > 0 {
            Some(tasks.get(1).expect("Error loading task 2"))
        }else{
            None
        }
    }

The goal is to return one "Task" object.
But I have the famous error :

returns a value referencing data owned by the current function

I don't understand how to return an object created inside a function like that...

If you return a non-'static reference, it must have been created from something you passed in (or you can return that reference alongside moving the newly created object it's derived from, but that's a different use case of returning two different things and doesn't apply here)

Unless &Task is owned by id or conn, the code you have here breaks that rule.

When you think about it, it makes sense from looking at what you have here... &Task is derived from all_tasks, but all_tasks is dropped when the function ends thereby invalidating the reference.

Here's a few options to consider:

  1. Return Task not &Task. You may need to clone()
  2. Return &'static Task if all_tasks is 'static
  3. Refactor to use the &Task without returning it, within the scope of that function, i.e. instead of get() you could have map() and pass in a closure or other function, something like:
pub fn map<F: FnOnce(&Task) -> A, A>(id: i32, conn:&PgConnection, mapper:F) -> Option<A> {
  let tasks = all_tasks.find(id).load::<Task>(conn).expect("Error loading task");
  if tasks.len() > 0 {
    Some(mapper(tasks.get(1).expect("Error loading task 2")))
  }  else{
    None
  }
}

You could then call it like:

let foo = map(42, &conn, |task| {
  // somehow get a String or whatever from the &Task
});

//foo is Option<String> or whatever the closure returned
println!("{:?}", foo)

Thank you !

1 Like