如何转换使用Read特性的代码来改为使用Iterator特征?

时间:2017-12-30 00:24:43

标签: iterator rust

我有一些解析文件的代码,非常类似于以下内容:

use std::io::Cursor;
use std::io::Result;
use std::io::Read;

fn main() {
   let v1 = [1, 2, 3, 4, 5];
   let mut c1 = Cursor::new(v1); // *

    println!("{:?}", read_one(&mut c1)); // 1
    println!("{:?}", read_three(&mut c1)); // 2, 3, 4     
    println!("{:?}", read_one(&mut c1)); // 5
    println!("{:?}", read_one(&mut c1)); // eof
}

fn read_one<R: Read>(r: &mut R) -> Result<u8> {
  let mut buf = [0; 1];
  r.read_exact(&mut buf)?;
  Ok(buf[0])
}

fn read_three<R: Read>(r: &mut R) -> Result<[u8; 3]> {
  let mut buf = [0; 3];
  r.read_exact(&mut buf)?;
  Ok(buf)
}

此处,read_oneread_three采用Read特征,从中获取一些字节,然后返回结果。然后我可以一块一块地读取字节。

我希望将此代码转换为使用迭代器。也就是说,让*行为

let mut i1 = v1.iter();

尝试这一点,我遇到了一些问题,我无法找到能够轻松提取多个项目(类似于read_exact)或以其他方式部分处理迭代器的函数。似乎大多数迭代器函数都是为了完全使用内容而设计的。

迭代器只是一个坏工具还是我使用它错了?如果是后者,我该如何将此代码转换为使用迭代器?

3 个答案:

答案 0 :(得分:3)

你可以为自己做出自己的特质

use std::io::{Error, ErrorKind, Result};

trait ReadExact {
    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>;
}

impl<T> ReadExact for T
where
    T: Iterator<Item = u8>,
{
    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
        for p in buf {
            if let Some(b) = self.next() {
                *p = b;
            } else {
                return Err(Error::new(ErrorKind::UnexpectedEof, "Iterator exhausted"));
            }
        }
        Ok(())
    }
}

list of characters

答案 1 :(得分:2)

以下是您可以collect into an array

的解释

如果您仍想使用迭代器,可以将返回类型更改为Vec 并打电话 r.take(n).collect();

然而,这会慢一些。

答案 2 :(得分:1)

你可以用迭代器写几乎相同的东西。您遇到的问题是阵列难以使用,因为他们不会(截至2017年12月)实施FromIterator。作为user1541501 suggested,最简单的解决方案是将collect()转换为Vec而不是:

fn main() {
    let v1 = vec![1, 2, 3, 4, 5];
    let mut c1 = v1.into_iter();

    println!("{:?}", read_one(&mut c1)); // 1
    println!("{:?}", read_three(&mut c1)); // 2, 3, 4
    println!("{:?}", read_one(&mut c1)); // 5
    println!("{:?}", read_one(&mut c1)); // eof
}

fn read_one<I: Iterator<Item = u8>>(i: &mut I) -> Option<u8> {
    i.next()
}

fn read_three<I: Iterator<Item = u8>>(i: &mut I) -> Result<Vec<u8>, Vec<u8>> {
    let buf: Vec<u8> = i.take(3).collect();
    if buf.len() == 3 {
        Ok(buf)
    } else {
        Err(buf)
    }
}

阵列也未实现IntoIterator,因此我将v1变为Vec<u8>以致电v1.into_iter()。您可以改为编写v1.iter().cloned()

我做的另一项重大更改是让read_one返回Option而不是io::Result,并使read_three返回Result<Vec<u8>, Vec<u8>>。这是因为迭代器只能通过耗尽数据而失败。 (如果read_three失败,则Err变体包含收集的元素。)