如何转换使用Read特性的代码来改为使用Iterator特征?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何转换使用Read特性的代码来改为使用Iterator特征?相关的知识,希望对你有一定的参考价值。
我有一些解析文件的代码,非常类似于以下内容:
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_one
和read_three
采用Read
特征,从中获取一些字节,并返回结果。然后我可以一块一块地读取字节。
我想将此代码转换为使用迭代器。也就是说,有*
线
let mut i1 = v1.iter();
尝试这个,我遇到了一些问题,我找不到函数来轻松提取多个项目(类似于read_exact
)或以其他方式部分处理迭代器。似乎大多数迭代器函数都是为了完全使用内容而设计的。
迭代器只是一个坏工具还是我使用它错了?如果是后者,如何将此代码转换为使用迭代器?
你可以用迭代器编写几乎相同的东西。您将遇到的问题是阵列很难使用,因为它们(截至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
变体包含收集的元素。)
你可以为此做出自己的特质
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(())
}
}
这里是为什么你不能collect into an array的解释
如果您仍想使用迭代器,可以将返回类型更改为Vec并调用r.take(n).collect();
然而,这会慢一点。
以上是关于如何转换使用Read特性的代码来改为使用Iterator特征?的主要内容,如果未能解决你的问题,请参考以下文章
如何在使用 pandas.read_csv 读取 csv 文件时将 pandas.dataframe 中的元素转换为 np.float?
如何在使用 pandas.read_csv 读取 csv 文件时将 pandas.dataframe 中的元素转换为 np.float?