Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何为迭代器实现std::io::Read?_Io_Iterator_Rust - Fatal编程技术网

如何为迭代器实现std::io::Read?

如何为迭代器实现std::io::Read?,io,iterator,rust,Io,Iterator,Rust,更具体地说,我采用了标准,使用.lines.filter\u映射过滤掉某些行,我想使用csv::Reader的结果。最简单的解决方案是将所有输入一次读取到一个巨大的缓冲区中,然后从中读取: let iterable = ["h", "e", "l", "l", "o"]; let combined_string: String = iterable.iter().cloned().collect(); let bytes = combined_string.into_bytes(); let

更具体地说,我采用了标准,使用.lines.filter\u映射过滤掉某些行,我想使用csv::Reader的结果。

最简单的解决方案是将所有输入一次读取到一个巨大的缓冲区中,然后从中读取:

let iterable = ["h", "e", "l", "l", "o"];
let combined_string: String = iterable.iter().cloned().collect(); 
let bytes = combined_string.into_bytes();

let mut buf = vec![];
let bytes = (&bytes[..]).read_to_end(&mut buf).unwrap();
assert_eq!(&buf[..bytes], b"hello");
如果您真的需要避免将其全部加载到内存中,那么可以实现一个包装器,但它有一些复杂的位,因为可用字节数和要读取的字节数并不总是匹配的。您必须保留一些临时值以跟踪您的位置,有时还需要获取更多数据以继续读取:

use std::io::{self, Read};
use std::cmp;

/// Eagerly consumes elements from the underlying iterator instead of
/// returning partial reads.
struct IteratorAsRead<I>
where
    I: Iterator,
{
    iter: I,
    value: Option<I::Item>,
    offset: usize,
}

impl<I> IteratorAsRead<I>
where
    I: Iterator,
{
    pub fn new<T>(iter: T) -> Self
    where
        T: IntoIterator<IntoIter = I, Item = I::Item>,
    {
        IteratorAsRead {
            iter: iter.into_iter(),
            value: None,
            offset: 0,
        }
    }
}

impl<I> Read for IteratorAsRead<I>
where
    I: Iterator,
    I::Item: AsRef<[u8]>,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut copied = 0;
        loop {
            match self.value.take() {
                None => {
                    match self.iter.next() {
                        None => {
                            return Ok(copied);
                        }
                        Some(value) => {
                            self.value = Some(value);
                        }
                    }
                }
                Some(original_value) => {
                    let entire_value_len = {
                        let entire_value = original_value.as_ref();

                        // Skip over bytes we already copied
                        let value = &entire_value[self.offset..];
                        let buf = &mut buf[copied..];

                        // Make the slices the same length
                        let len_to_copy = cmp::min(value.len(), buf.len());
                        let value = &value[..len_to_copy];
                        let buf = &mut buf[..len_to_copy];

                        // Copy
                        buf.copy_from_slice(value);

                        // Advance our values
                        copied += len_to_copy;
                        self.offset += len_to_copy;

                        entire_value.len()
                    };

                    // If we completely used the value, reset our counters,
                    // otherwise put it back for the next call.
                    if self.offset == entire_value_len {
                        self.offset = 0;
                    } else {
                        self.value = Some(original_value);
                    }
                }
            }

            // If we've filled the buffer, return it
            if copied == buf.len() {
                return Ok(copied);
            }
        }
    }
}

#[test]
fn small_pieces_are_combined() {
    let iterable = ["h", "e", "l", "l", "o"];
    let mut reader = IteratorAsRead::new(&iterable);

    let mut buf = vec![];
    let bytes = reader.read_to_end(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"hello");
}

#[test]
fn partial_reads() {
    let iterable = ["hello"];
    let mut reader = IteratorAsRead::new(&iterable);

    let mut buf = [0; 2];

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"he");

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"ll");

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"o");
}

最简单的解决方案是将所有输入一次读入一个巨大的缓冲区,然后从中读取:

let iterable = ["h", "e", "l", "l", "o"];
let combined_string: String = iterable.iter().cloned().collect(); 
let bytes = combined_string.into_bytes();

let mut buf = vec![];
let bytes = (&bytes[..]).read_to_end(&mut buf).unwrap();
assert_eq!(&buf[..bytes], b"hello");
如果您真的需要避免将其全部加载到内存中,那么可以实现一个包装器,但它有一些复杂的位,因为可用字节数和要读取的字节数并不总是匹配的。您必须保留一些临时值以跟踪您的位置,有时还需要获取更多数据以继续读取:

use std::io::{self, Read};
use std::cmp;

/// Eagerly consumes elements from the underlying iterator instead of
/// returning partial reads.
struct IteratorAsRead<I>
where
    I: Iterator,
{
    iter: I,
    value: Option<I::Item>,
    offset: usize,
}

impl<I> IteratorAsRead<I>
where
    I: Iterator,
{
    pub fn new<T>(iter: T) -> Self
    where
        T: IntoIterator<IntoIter = I, Item = I::Item>,
    {
        IteratorAsRead {
            iter: iter.into_iter(),
            value: None,
            offset: 0,
        }
    }
}

impl<I> Read for IteratorAsRead<I>
where
    I: Iterator,
    I::Item: AsRef<[u8]>,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut copied = 0;
        loop {
            match self.value.take() {
                None => {
                    match self.iter.next() {
                        None => {
                            return Ok(copied);
                        }
                        Some(value) => {
                            self.value = Some(value);
                        }
                    }
                }
                Some(original_value) => {
                    let entire_value_len = {
                        let entire_value = original_value.as_ref();

                        // Skip over bytes we already copied
                        let value = &entire_value[self.offset..];
                        let buf = &mut buf[copied..];

                        // Make the slices the same length
                        let len_to_copy = cmp::min(value.len(), buf.len());
                        let value = &value[..len_to_copy];
                        let buf = &mut buf[..len_to_copy];

                        // Copy
                        buf.copy_from_slice(value);

                        // Advance our values
                        copied += len_to_copy;
                        self.offset += len_to_copy;

                        entire_value.len()
                    };

                    // If we completely used the value, reset our counters,
                    // otherwise put it back for the next call.
                    if self.offset == entire_value_len {
                        self.offset = 0;
                    } else {
                        self.value = Some(original_value);
                    }
                }
            }

            // If we've filled the buffer, return it
            if copied == buf.len() {
                return Ok(copied);
            }
        }
    }
}

#[test]
fn small_pieces_are_combined() {
    let iterable = ["h", "e", "l", "l", "o"];
    let mut reader = IteratorAsRead::new(&iterable);

    let mut buf = vec![];
    let bytes = reader.read_to_end(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"hello");
}

#[test]
fn partial_reads() {
    let iterable = ["hello"];
    let mut reader = IteratorAsRead::new(&iterable);

    let mut buf = [0; 2];

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"he");

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"ll");

    let bytes = reader.read(&mut buf).unwrap();
    assert_eq!(&buf[..bytes], b"o");
}

如果允许Read::Read返回部分读取,则有一个简单的Read::Read实现。从与Shepmaster类似的结构开始

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

struct IteratorAsRead<I>
where
    I: Iterator,
{
    iter: I,
    leftover: Option<(I::Item, usize)>,
}

impl<I> IteratorAsRead<I>
where
    I: Iterator,
{
    pub fn new<T>(iter: T) -> Self
    where
        T: IntoIterator<IntoIter = I, Item = I::Item>,
    {
        IteratorAsRead {
            iter: iter.into_iter(),
            leftover: None,
        }
    }
}
然后实现该函数,首先查找要读取的非空字符串,尝试将其写入缓冲区,最后根据需要存储任何剩余内容

impl<I> Read for IteratorAsRead<I>
where
    I: Iterator,
    I::Item: AsRef<[u8]>,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let (leftover, skip) = match self.leftover.take() {
            Some(last) => last,
            None => match self.iter.find(|next| !next.as_ref().is_empty()) {
                Some(next) => (next, 0),
                None => return Ok(0),
            }
        };

        let read = (&leftover.as_ref()[skip..]).read(buf)?;

        if skip + read < leftover.as_ref().len() {
            self.leftover = Some((leftover, skip + read));
        } else {
            self.leftover = None;
        }

        return Ok(read);
    }
}

如果允许Read::Read返回部分读取,则有一个简单的Read::Read实现。从与Shepmaster类似的结构开始

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

struct IteratorAsRead<I>
where
    I: Iterator,
{
    iter: I,
    leftover: Option<(I::Item, usize)>,
}

impl<I> IteratorAsRead<I>
where
    I: Iterator,
{
    pub fn new<T>(iter: T) -> Self
    where
        T: IntoIterator<IntoIter = I, Item = I::Item>,
    {
        IteratorAsRead {
            iter: iter.into_iter(),
            leftover: None,
        }
    }
}
然后实现该函数,首先查找要读取的非空字符串,尝试将其写入缓冲区,最后根据需要存储任何剩余内容

impl<I> Read for IteratorAsRead<I>
where
    I: Iterator,
    I::Item: AsRef<[u8]>,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let (leftover, skip) = match self.leftover.take() {
            Some(last) => last,
            None => match self.iter.find(|next| !next.as_ref().is_empty()) {
                Some(next) => (next, 0),
                None => return Ok(0),
            }
        };

        let read = (&leftover.as_ref()[skip..]).read(buf)?;

        if skip + read < leftover.as_ref().len() {
            self.leftover = Some((leftover, skip + read));
        } else {
            self.leftover = None;
        }

        return Ok(read);
    }
}

标准库提供将缓冲区与缓冲区中的位置包装在一起的类型。这可用于进一步简化以下代码:


标准库提供将缓冲区与缓冲区中的位置包装在一起的类型。这可用于进一步简化以下代码:


这个问题来自IRC.mozilla.org上Rust中的Rust IRC用户njoodle,但IRC日志在这段时间内似乎不起作用,因此我无法提供更完整的作者链接。这个问题来自IRC.mozilla.org上Rust中的Rust IRC用户njoodle,但IRC日志记录似乎在这段时间内不起作用,因此我无法提供更完整的作者链接。我使用std::io::Cursor发布了一个更简单的版本–请参见我的答案。我使用std::io::Cursor发布了一个更简单的版本–请参见我的答案。这里有一个impl Read for Cursor,其中t:AsRef,所以你甚至不需要限制元素类型。@Veedrac你是对的,我不需要那个限制。我引入它主要是为了避免将游标包装在选项中,但即使这样,它也可以再次变得更通用。使用默认值时,构造函数应该调用Cursor.set_positionnext.len来处理非空的类型,例如静态大小的数组。@Veedrac哦,我没有想到这种可能性。不过,我认为我不能使用len,因为它没有特性,所以我可能需要再次将光标包装在一个选项中。切片有len,所以我可以简单地将AsRef添加到构造函数中。这里有一个impl Read for cursor,其中t:AsRef,所以您甚至不必限制元素类型。@Veedrac您是对的,我不需要那个限制。我引入它主要是为了避免将游标包装在选项中,但即使这样,它也可以再次变得更通用。使用默认值时,构造函数应该调用Cursor.set_positionnext.len来处理非空的类型,例如静态大小的数组。@Veedrac哦,我没有想到这种可能性。但是我不认为我可以使用len,因为它没有特性,所以我可能需要再次将光标包装在一个选项中。切片有len,所以我可以简单地将AsRef添加到构造函数中。