Вы не можете. Вместо этого вам нужно будет клонировать итератор или какой-то его строительный блок. В этом случае самое высокое, что вы можете клонировать, это Cursor
:
use std::io::{self, BufRead};
fn main() {
let cursor = io::Cursor::new(b"pillow\nbrick\r\nphone");
let lines = cursor.clone().lines().map(|l| l.unwrap());
let lines2 = cursor.lines().map(|l| l.unwrap());
let soft_count = lines.filter(|line| line.contains("pillow")).count();
let hard_count = lines2.filter(|line| !line.contains("pillow")).count();
}
Для фактического File
вам нужно будет использовать try_clone
, так как он может потерпеть неудачу , В любом случае вы будете ссылаться на одни и те же данные дважды, и будет храниться только информация итератора.
Для вашего конкретного случая c вам это не нужно. Фактически, повторение данных дважды неэффективно. Самая простая встроенная вещь, которую вы можете сделать, это partition
итератор:
let (softs, hards): (Vec<_>, Vec<_>) = lines.partition(|line| line.contains("pillow"));
let soft_count = softs.len();
let hard_count = hards.len();
Это все еще немного неэффективно, поскольку вам не нужны фактические значения. Вы можете создать свой собственный тип, который реализует Extend
и отбрасывает значения:
#[derive(Debug, Default)]
struct Count(usize);
impl<T> std::iter::Extend<T> for Count {
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator,
{
self.0 += iter.into_iter().count();
}
}
let (softs, hards): (Count, Count) = lines.partition(|line| line.contains("pillow"));
let soft_count = softs.0;
let hard_count = hards.0;
Вы также можете просто использовать for
l oop или построить что-то поверх fold
:
let (soft_count, hard_count) = lines.fold((0, 0), |mut state, line| {
if line.contains("pillow") {
state.0 += 1;
} else {
state.1 += 1;
}
state
});