file-io - 如何使多个迭代器可以处理与文件有关的相同数据?

标签 file-io rust iterator

我有一个文件,希望将其读取并将数据过滤成两个不同的集合,并确定每个集合中的项数。

use std::io::{self, BufRead};

fn main() {
    let cursor = io::Cursor::new(b"pillow\nbrick\r\nphone");

    let lines = cursor.lines().map(|l| l.unwrap());

    let soft_count = lines.filter(|line| line.contains("pillow")).count();

    let hard_count = lines.filter(|line| !line.contains("pillow")).count();
}
  • Playground
  • GitHub

  • 但是,借阅检查器给我一个错误:

    error[E0382]: use of moved value: `lines`
      --> src/main.rs:14:22
       |
    8  |     let lines = cursor.lines().map(|l| l.unwrap());
       |         ----- move occurs because `lines` has type `std::iter::Map<std::io::Lines<std::io::Cursor<&[u8; 19]>>, [closure@src/main.rs:8:36: 8:50]>`, which does not implement the `Copy` trait
    9  |     
    10 |     let soft_count = lines
       |                      ----- value moved here
    ...
    14 |     let hard_count = lines
       |                      ^^^^^ value used here after move
    

    我尝试使用引用计数解决此问题,以允许多个所有权:

    use std::io::{self, BufRead};
    use std::rc::Rc;
    
    fn main() {
        let cursor = io::Cursor::new(b"pillow\nbrick\r\nphone");
    
        let lines = Rc::new(cursor.lines().map(|l| l.unwrap()));
    
        let soft_count = Rc::clone(&lines)
            .filter(|line| line.contains("pillow"))
            .count();
    
        let hard_count = Rc::clone(&lines)
            .filter(|line| !line.contains("pillow"))
            .count();
    }
    
  • Playground
  • Github

  • 我收到类似的错误消息:

    error[E0507]: cannot move out of an `Rc`
      --> src/main.rs:11:22
       |
    11 |     let soft_count = Rc::clone(&lines)
       |                      ^^^^^^^^^^^^^^^^^ move occurs because value has type `std::iter::Map<std::io::Lines<std::io::Cursor<&[u8; 19]>>, [closure@src/main.rs:9:44: 9:58]>`, which does not implement the `Copy` trait
    
    error[E0507]: cannot move out of an `Rc`
      --> src/main.rs:15:22
       |
    15 |     let hard_count = Rc::clone(&lines)
       |                      ^^^^^^^^^^^^^^^^^ move occurs because value has type `std::iter::Map<std::io::Lines<std::io::Cursor<&[u8; 19]>>, [closure@src/main.rs:9:44: 9:58]>`, which does not implement the `Copy` trait
    

    最佳答案

    你不能。相反,您将需要克隆迭代器或它的某些构建块。在这种情况下,您可以克隆的最高名称是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 ,因为它可能会失败。无论哪种情况,您都将两次引用相同的数据,并且仅保留迭代器信息。

    对于您的特定情况,您不需要任何这些。实际上,对数据进行两次迭代效率不高。您可以执行的最简单的内置操作是 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循环或在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
    });
    

    关于file-io - 如何使多个迭代器可以处理与文件有关的相同数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60160391/

    相关文章:

    c - c语言中如何打开子目录下的文件

    java - 一个类可以有自己的私有(private)PrintWriter吗?

    function-pointers - 如何在 Rust 中将匿名函数作为参数传递?

    generics - 名称 `T`已用于通用参数

    java - 连续对象值提取器的设计模式

    javascript - 使用 JavaScript 迭代器的困难

    C++ 在eof() 之后继续读取文件?

    java - 在 Android 中从文件读取/写入字符串

    vector - 可以在没有额外分配的情况下移动和修改矢量吗?

    java - 遍历集合集合