File io 如何对同一个文件的相同数据使用多个迭代器?

File io 如何对同一个文件的相同数据使用多个迭代器?,file-io,rust,iterator,File Io,Rust,Iterator,我有一个文件,我希望读取和过滤数据到两个不同的集合,并确定每个集合中的项目数 使用std::io:{self,BufRead}; fn main(){ 让cursor=io::cursor::new(b“抱枕\n点击\r\n电话”); 设lines=cursor.lines().map(|l | l.unwrap()); 让soft_count=lines.filter(| line | line.contains(“枕头”)).count(); 让hard_count=lines.filter

我有一个文件,我希望读取和过滤数据到两个不同的集合,并确定每个集合中的项目数

使用std::io:{self,BufRead};
fn main(){
让cursor=io::cursor::new(b“抱枕\n点击\r\n电话”);
设lines=cursor.lines().map(|l | l.unwrap());
让soft_count=lines.filter(| line | line.contains(“枕头”)).count();
让hard_count=lines.filter(| line |!line.contains(“枕头”)).count();
}
但是,“借用检查器”给了我一个错误:

错误[E0382]:使用移动值:`line`
-->src/main.rs:14:22
|
8 |让线=游标.lines().map(| l | l.unwrap());
|----发生移动是因为'lines'的类型为'std::iter::Map',而该类型不实现'Copy'特性
9  |     
10 |让软计数=线
|----值移到了这里
...
14 |让硬计数=行
|^^^^^移动后此处使用的值
我尝试使用引用计数来解决此问题,以允许多重所有权:

使用std::io:{self,BufRead};
使用std::rc::rc;
fn main(){
让cursor=io::cursor::new(b“抱枕\n点击\r\n电话”);
让lines=Rc::new(cursor.lines().map(|l | l.unwrap());
让软计数=Rc::克隆(&行)
.filter(| line | line.contains(“枕头”))
.count();
让硬计数=Rc::克隆(&行)
.filter(| line |!line.contains(“枕头”))
.count();
}
我收到一条类似的错误消息:

错误[E0507]:无法移出'Rc'`
-->src/main.rs:11:22
|
11 |让软计数=Rc::克隆(&行)
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
错误[E0507]:无法移出'Rc'`
-->src/main.rs:15:22
|
15 |让硬计数=Rc::克隆(&行)
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

您不能。相反,您需要克隆迭代器,或者它的某些构建块。在这种情况下,可以克隆的最高对象是
光标

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();
}
对于实际的
文件
,您需要使用,因为它可能会失败。在这两种情况下,您将引用相同的数据两次,并且只保留迭代器信息


对于您的具体情况,您不需要这些。事实上,对数据进行两次迭代是低效的。您可以做的最简单的内置操作是使用迭代器:

let (softs, hards): (Vec<_>, Vec<_>) = lines.partition(|line| line.contains("pillow"));

let soft_count = softs.len();
let hard_count = hards.len();
您也可以只使用
进行
循环,或在
折叠上构建一些东西:

let (soft_count, hard_count) = lines.fold((0, 0), |mut state, line| {
    if line.contains("pillow") {
        state.0 += 1;
    } else {
        state.1 += 1;
    }
    state
});

感谢您如此周到的回复@Shepmaster。还有一个问题。假设您确实需要收集这些集合,并且它们不是互斥的,那么您的第一个建议是复制数据并迭代两次吗?我决定确定每个集合的大小的原因是为了避免碎片,同时分配内存。collect方法可以做到这一点吗?还是以单个增量请求内存?这取决于迭代器的
实现者决定是否使用迭代器的
大小提示来预先分配内存。我通常认为标准库中的实现是基于它所拥有的信息的智能实现。如果你有信息,但没有,你可能能够提供帮助,但我不会担心,直到你有了适当的基准来衡量。阅读一个具体的例子。对于双重迭代和复制数据有类似的想法。我认为这将归结于重叠有多大以及复制有多昂贵。基准测试是了解哪种方法更适合您的数据的最佳工具。
let (softs, hards): (Count, Count) = lines.partition(|line| line.contains("pillow"));

let soft_count = softs.0;
let hard_count = hards.0;
let (soft_count, hard_count) = lines.fold((0, 0), |mut state, line| {
    if line.contains("pillow") {
        state.0 += 1;
    } else {
        state.1 += 1;
    }
    state
});