Ответ 1
Давайте сравним 4 подхода.
1. Read::chars
Вы могли бы скопировать Read::chars
, но он нестабилен с
семантика частичного чтения/записи, где происходят ошибки, в настоящее время неясна и может изменить
поэтому необходимо проявить некоторую осторожность. Во всяком случае, это, по-видимому, лучший подход.
2. flat_map
Альтернатива flat_map
не компилируется:
use std::io::{BufRead, BufReader};
use std::fs::File;
pub fn main() {
let mut f = BufReader::new(File::open("input.txt").expect("open failed"));
for c in f.lines().flat_map(|l| l.expect("lines failed").chars()) {
println!("Character: {}", c);
}
}
Проблема заключается в том, что chars
берет из строки, но l.expect("lines failed")
живет только внутри замыкания, поэтому компилятор дает ошибку borrowed value does not live long enough
.
3. Вложенный для
Этот код
use std::io::{BufRead, BufReader};
use std::fs::File;
pub fn main() {
let mut f = BufReader::new(File::open("input.txt").expect("open failed"));
for line in f.lines() {
for c in line.expect("lines failed").chars() {
println!("Character: {}", c);
}
}
}
работает, но он сохраняет выделение строки для каждой строки. Кроме того, если в входном файле нет разрыва строки, весь файл будет загружен в память.
4. BufRead::read_until
Эффективной альтернативой памяти для подхода 3 является использование Read::read_until
и использование одной строки для чтения каждой строки:
use std::io::{BufRead, BufReader};
use std::fs::File;
pub fn main() {
let mut f = BufReader::new(File::open("input.txt").expect("open failed"));
let mut buf = Vec::<u8>::new();
while f.read_until(b'\n', &mut buf).expect("read_until failed") != 0 {
// this moves the ownership of the read data to s
// there is no allocation
let s = String::from_utf8(buf).expect("from_utf8 failed");
for c in s.chars() {
println!("Character: {}", c);
}
// this returns the ownership of the read data to buf
// there is no allocation
buf = s.into_bytes();
buf.clear();
}
}