Simple Function Returning a Vec

Hello all,
I have what I think is a simple question, but I have been unable to figure out how to setup this function.
The function reads the text of an input file, splits the lines, filters out empty values, and collects the values into a Vec.
What I want to do is return the Vec, but so far I have not been able to figure out how to correct the errors... I have tried to add a lifetime but I barely understand how those are used, I tried clone() and to_owned(), and a few other things but so far nothing has worked.

pub fn read_input_file(file_name: &str) -> Vec<&str> {
    std::fs::read_to_string(file_name)
        .unwrap()
        .split('\n')
        .into_iter()
        .filter(|s| !s.is_empty())
        .collect();
    list
}

The error I am getting with this code is:

error[E0515]: cannot return value referencing temporary value
  --> src/utils.rs:23:5
   |
23 |        std::fs::read_to_string(file_name)
   |   _____^
   |  |_____|
   | ||
24 | ||         .unwrap()
   | ||_________________- temporary value created here
25 | |          .split('\n')
26 | |          .into_iter()
27 | |          .filter(|s| !s.is_empty())
28 | |          .collect()
   | |___________________^ returns a value referencing data owned by the current function

Please advise, thanks!

Type &str isn't a thing that can exist on its own. It's a type that is temporarily borrowing from a String or a similar owned type that has to be stored somewhere for as long as &str exists.

In your case the String from read_to_string isn't stored anywhere. It's used in a temporary expression and then thrown away. So you can't return a view into that string — the borrow checker has caught a use-after-free bug in your code.

You have to return Vec<String>, so that it's a self-contained type without being tied to any variable or temporary data inside the function. Add .map(|s| s.to_owned()) or .map(String::from) before .collect().

Rust doesn't have garbage collection, so it can't automatically make anything live longer. All the variables are destroyed at the end of their scope, so you can't return anything that borrows from a variable (or a temporary expression).

4 Likes

(kornel basically already said this, but)

Without looking at the body one can tell that this won't work. That function definition (because of lifetime elision) says that the returns strings are borrowed from the input string, but that can't be what's wanted based on the implication of the function name.

See how the read_to_string you're calling is returning Something<String>, not Something<&str> -- it does that for the same reason you need String here.

3 Likes

Wow, you guys are fast!
@kornel that was it, changing the return to Vec<String> and adding in a map(String::from) call before the collect() works as intended.
@scottmcm thanks for pointing out the example in the read_to_string method, very helpful to see examples.
I figured it was something simple, thank you both for your help, much appreciated!

here is the updated working function.

pub fn read_input_file(file_name: &str) -> Vec<String> {
    std::fs::read_to_string(file_name)
        .unwrap()
        .split('\n')
        .into_iter()
        .filter(|s| !s.is_empty())
        .map(String::from)
        .collect()
}
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.