How to return the first item in a list from a function

fn foo() -> Option<&String> {
  let list = [
    "string1".to_string(),
    "string2".to_string(),
  ];

  let y = list.first();
  y
}

I want to return y but it is of type Option<&String>

I can't figure out how to make this work as if I change the return type to Option<&String> it gives a missing lifetime specifier this function's return type contains a borrowed value, but there is no value for it to be borrowed from error.

I don't really understand this error... clearly there is something I'm not understanding here as I see no reason why this doesn't work... any ideas how to fix this?

Rust cares a lot about ownership.
Your function creates the list, hence owns it.
You want to return a borrow, since you have a &.
This is not ok, because your function will clean up.
So, once you return from the function, the list will no longer exist. Hence the first element will no longer exist, and thus your return value is a dangling Pointer .

Solution:
Change the return type to Option, and clone.
Then you return owned data, which will deallocate itself when it goes out of acope later in your app.
This is maybe the best solution.

Other solution:
Move the list to global scope, making it static or constant.
This solution is maybe "experts only"

Third solution:
Change the return type to Option<&'static str>.
This is also a good solution, but less flexibel than the first. Why?

The String that you have a reference to goes out of scope at the end of foo, at which point the memory containing the string is destroyed. You cannot return a reference to a destroyed string.

2 Likes

You can move elements out of the array by converting the array into an iterator:

fn foo() -> Option<String> {
  let list = [
    "string1".to_string(),
    "string2".to_string(),
  ];

  list.into_iter().next()
}
3 Likes

Temporary loans (&) can't exist on their own. They always borrow from something else that must have a permanent storage. This is very different from languages with a garbage collector where "returning by reference" is possible.

Basically, if a function doesn't take arguments, it can't temporarily lend anything (can't have & in the return type).

foo(list: &[String]) -> Option<&String>

is possible, but:

foo() -> Option<&String>

makes no sense in Rust.

There's a special case of leaked memory -> Option<&'static String>, but it's almost never useful in real-world code.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.