1

I need help regarding how to convert file input taken as a string to an vector. I tried

let content = fs::read_to_string(file_path).expect("Failed to read input");
let content: Vec<&str> = content.split("\n").collect();

This works, but I wanted to convert it to one statement. Something like

let content: Vec<&str> = fs::read_to_string(file_path)
    .expect("Failed to read input")
    .split("\n")
    .collect();

I tried using

let content: Vec<&str> = match fs::read_to_string(file_path) {
    Ok(value) => value.split("\n").collect(),
    Err(err) => {
        println!("Error Unable to read the file {}", err);
        return ();
    }
};

and

let content: Vec<&str> = match fs::read_to_string(file_path) {
    Ok(value) => value,
    Err(err) => {
        println!("Error Unable to read the file {}", err);
        return ();
    }
}
.split("\n")
.collect();

The compiler says that the borrowed values does not live long enough (1st) and value in freed while in use (2nd) (problem with borrowing, scope and ownership).

error[E0716]: temporary value dropped while borrowed
 --> src/lib.rs:4:26
  |
4 |   let content: Vec<&str> = fs::read_to_string("")
  |  __________________________^
5 | |     .expect("Failed to read input")
  | |___________________________________^ creates a temporary which is freed while still in use
6 |       .split("\n")
7 |       .collect();
  |                 - temporary value is freed at the end of this statement
8 |       
9 |       dbg!(content);
  |            ------- borrow later used here
  |
  = note: consider using a `let` binding to create a longer lived value

I still lack much understanding about how to fix them.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Anupam Minz
  • 125
  • 1
  • 7

2 Answers2

2

It is impossible to do this in one expression. Use two expressions with a let, as you already are and as the compiler tells you.


The problem is that split produces string slices (&str) that reference the temporary String. That String is deallocated at the end of the statement, making the references invalid. Rust is preventing you from introducing memory unsafety:

fs::read_to_string(file_path)        // Creates a String
    .expect("Failed to read input")
    .split("\n")                     // Takes references into the String
    .collect();                      // String is dropped, invalidating references

If you didn't need a Vec<&str>, you could have a Vec<String>:

fs::read_to_string(file_path)
    .expect("Failed to read input")
    .split("\n")
    .map(|s| s.to_string())         // Convert &str to String
    .collect();

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
2

You create a String with read_to_string, but it is not bound to any variable because you are using it right after by using it with split. The String is the temporary variable mentioned in the error. It is not bound to anything. The split function returns references to the contents of the string... but this String will be deallocated by the end of the line, because again, it is not bound to a variable.

If you really need to do it in one line, but a bit less efficiently:

let content: Vec<String> = fs::read_to_string(file_path)
    .expect("Failed to read input")
    .split("\n")
    .map(|line| line.to_string())
    .collect();
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
LeoVen
  • 632
  • 8
  • 18