DK.’s answer is quite right and has great explanation. However, you stated:
Read a file and get an array of strings
Rust arrays have a fixed length, known at compile time, so I assume you really mean “vector”. I would write it like this:
use std::{
fs::File,
io::{prelude::*, BufReader},
path::Path,
};
fn lines_from_file(filename: impl AsRef<Path>) -> Vec<String> {
let file = File::open(filename).expect("no such file");
let buf = BufReader::new(file);
buf.lines()
.map(|l| l.expect("Could not parse line"))
.collect()
}
// ---
fn main() {
let lines = lines_from_file("/etc/hosts");
for line in lines {
println!("{:?}", line);
}
}
- As in the other answer, it’s worth it to use a generic type that implements
AsReffor the filename. Result::expectshortens the panic onErr.BufRead::lineshandles multiple types of newlines, not just"\n".BufRead::linesalso gives you separately allocatedStrings, instead of one big glob.- There’s no reason to collect to a temporary variable just to return it. There’s especially no reason to repeat the type (
Vec<String>).
If you wanted to return a Result on failure, you can squash the implementation down to one line if you want:
use std::{
fs::File,
io::{self, BufRead, BufReader},
path::Path,
};
fn lines_from_file(filename: impl AsRef<Path>) -> io::Result<Vec<String>> {
BufReader::new(File::open(filename)?).lines().collect()
}
// ---
fn main() {
let lines = lines_from_file("/etc/hosts").expect("Could not load lines");
for line in lines {
println!("{:?}", line);
}
}