У меня есть структура данных, в которой я предоставляю обертку вокруг буфера чтения для автоматической обработки повторяющихся операторов в считывании.
Это делается путем сохранения внутреннего состояния количества оставшихся повторов иПовторяющаяся строка.
use std::fs::File;
use std::path::Path;
use std::io::BufReader;
use std::io::prelude::*;
use std::io::Error;
use std::num::NonZeroU32;
use std::mem;
pub struct Reader {
handle: BufReader<File>,
repeat_state: Option<(NonZeroU32, String)>,
}
impl Reader {
pub fn new<P: AsRef<Path>>(path: P) -> Result<Reader, Error> {
let file = File::open(path)?;
let handle = BufReader::new(file);
Ok(Reader {
handle,
repeat_state: None,
})
}
/// get next line, respecting repeat instructions
pub fn next_line(&mut self) -> Option<String> {
if self.repeat_state.is_some() {
let (repeats_left, last_line) = mem::replace(&mut self.repeat_state, None).unwrap();
self.repeat_state = NonZeroU32::new(repeats_left.get() - 1)
.map(|repeats_left| (repeats_left, last_line.clone()));
Some(last_line)
} else {
let mut line = String::new();
if self.handle.read_line(&mut line).is_err() || line.is_empty() {
return None
}
if line.starts_with("repeat ") {
let repeats: Option<u32> = line.chars().skip(7)
.take_while(|c| c.is_numeric())
.collect::<String>().parse().ok();
self.repeat_state = repeats
.and_then(|repeats| NonZeroU32::new(repeats - 1))
.map(|repeats_left| (repeats_left, line.clone()))
}
Some(line)
}
}
}
#[test]
fn test_next_line() {
let source = "
line one
repeat 2 line two and line three
line four
repeat 11 lines 5-15
line 16
line 17
last line (18)
".trim();
let mut input = File::create("file.txt").unwrap();
write!(input, "{}", source);
let mut read = Reader::new("file.txt").unwrap();
assert_eq!(
read.next_line(),
Some("line one\n".to_string())
);
assert_eq!(
read.next_line(),
Some("repeat 2 line two and line three\n".to_string())
);
assert_eq!(
read.next_line(),
Some("repeat 2 line two and line three\n".to_string())
);
assert_eq!(
read.next_line(),
Some("line four\n".to_string())
);
for _ in 5..=15 {
assert_eq!(
read.next_line(),
Some("repeat 11 lines 5-15\n".to_string())
);
}
assert_eq!(
read.next_line(),
Some("line 16\n".to_string())
);
assert_eq!(
read.next_line(),
Some("line 17\n".to_string())
);
assert_eq!(
read.next_line(),
Some("last line (18)".to_string())
);
}
Детская площадка
Проблема заключается в том, что мне приходится каждый раз клонировать удерживаемое повторяющееся значение, чтобы удерживать его и возвращатьЭто.Я хочу избежать этих дорогостоящих клонов, возвращая (и, возможно, сохраняя) &str
.Я перепробовал несколько вещей, но не смог заставить его работать:
- Сохранение
String
, возвращение &str
: ошибки "не живут достаточно долго" - Хранение
&str
, возвращение &str
: те же ошибки времени жизни Cow<&str>
Box<&str>
Эти клоны являются узким местом моей программы намомент, согласно профилировщику выборки на основе времени CodeXL после сборки в режиме выпуска с информацией отладки.Теперь моя программа довольно быстрая, но мне интересно, есть ли способ их избежать.