Используйте sample_iter
для случайной выборки из итератора с использованием выборка из резервуара .Он будет сканировать весь файл один раз, создавая String
с для каждой строки, но не будет создавать гигантский вектор для каждой строки:
fn find_word() -> String {
let f = File::open(FILENAME)
.unwrap_or_else(|e| panic!("(;_;) file not found: {}: {}", FILENAME, e));
let f = BufReader::new(f);
let lines = f.lines().map(|l| l.expect("Couldn't read line"));
match rand::seq::sample_iter(&mut rand::thread_rng(), lines, 1) {
Ok(mut v) => v.pop().unwrap(),
Err(_) => panic!("File had no lines"),
}
}
expect(&format!("..."))
Не делайте этого, он безусловно выделяет память .Когда нет сбоев, это распределение тратится впустую.Используйте unwrap_or_else
, как показано.
Ваша первоначальная проблема заключается в том, что:
slice::get
возвращает необязательную ссылку на вектор.
Вы можете либо клонировать это, либо стать владельцем значения:
let line = lines[n].cloned()
let line = lines.swap_remove(n)
Обе эти паники, если n
выходит за пределы, чторазумно здесь, поскольку вы знаете, что вы находитесь в пределах.
BufRead::lines
возвращает
io::Result<String>
, поэтому вы должны обработать этот случай ошибки.