【问题标题】:How to read (std::io::Read) from a Vec or Slice?如何从 Vec 或 Slice 中读取 (std::io::Read)?
【发布时间】:2017-02-15 04:17:01
【问题描述】:

Vecs 支持std::io::Write,因此可以编写采用FileVec 的代码,例如。从 API 参考来看,Vec 和 slice 似乎都不支持 std::io::Read

有没有方便的方法来实现这一点?是否需要编写包装结构?

这是一个工作代码示例,它读取和写入一个文件,其中一行注释应该读取一个向量。

use ::std::io;

// Generic IO
fn write_4_bytes<W>(mut file: W) -> Result<usize, io::Error>
    where W: io::Write,
{
    let len = file.write(b"1234")?;
    Ok(len)
}

fn read_4_bytes<R>(mut file: R) -> Result<[u8; 4], io::Error>
    where R: io::Read,
{
    let mut buf: [u8; 4] = [0; 4];
    file.read(&mut buf)?;
    Ok(buf)
}

// Type specific

fn write_read_vec() {
    let mut vec_as_file: Vec<u8> = Vec::new();

    {   // Write
        println!("Writing Vec... {}", write_4_bytes(&mut vec_as_file).unwrap());
    }

    {   // Read
//      println!("Reading File... {:?}", read_4_bytes(&vec_as_file).unwrap());
        //                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        //                               Comment this line above to avoid an error!
    }
}

fn write_read_file() {
    let filepath = "temp.txt";
    {   // Write
        let mut file_as_file = ::std::fs::File::create(filepath).expect("open failed");
        println!("Writing File... {}", write_4_bytes(&mut file_as_file).unwrap());
    }

    {   // Read
        let mut file_as_file = ::std::fs::File::open(filepath).expect("open failed");
        println!("Reading File... {:?}", read_4_bytes(&mut file_as_file).unwrap());
    }
}

fn main() {
    write_read_vec();
    write_read_file();
}

这失败并出现错误:

error[E0277]: the trait bound `std::vec::Vec<u8>: std::io::Read` is not satisfied
  --> src/main.rs:29:42
   |
29 |         println!("Reading File... {:?}", read_4_bytes(&vec_as_file).unwrap());
   |                                          ^^^^^^^^^^^^ the trait `std::io::Read` is not implemented for `std::vec::Vec<u8>`
   |
   = note: required by `read_4_bytes`

我想为文件格式编码器/解码器编写测试,而不必写入文件系统。

【问题讨论】:

  • 我已经删除了我的答案。这个问题现在明显更大,并且提供了比最初提出的问题更多的上下文
  • @simon-whitehead,很抱歉一开始没有给出一个全面的问题,我想我可能遗漏了一些完全明显的东西,不需要工作代码示例。

标签: io rust traits


【解决方案1】:

虽然向量不支持std::io::Read,但切片可以。

这里有一些混乱,因为 Rust 能够在某些情况下将 Vec 强制转换为切片,但在其他情况下则不行。

在这种情况下,需要对切片进行显式强制,因为在应用强制的阶段,编译器不知道Vec&lt;u8&gt; 实现Read


当使用以下方法之一将向量强制为切片时,问题中的代码将起作用:

  • read_4_bytes(&amp;*vec_as_file)
  • read_4_bytes(&amp;vec_as_file[..])
  • read_4_bytes(vec_as_file.as_slice())

注意:

  • 最初问这个问题时,我选择的是&amp;Read,而不是Read。这使得传递对切片的引用失败,除非我传入了 &amp;&amp;*vec_as_file,但我没想到这样做。
  • Rust 的最新版本,您还可以使用 as_slice() 将 Vec 转换为切片。
  • 感谢@arete on #rust 找到解决方案!

【讨论】:

  • 在更新的 rust 版本中,您还可以使用 as_slice()Vec 转换为切片,然后您可以使用 Read 中的方法。
【解决方案2】:

std::io::光标

std::io::Cursor 是一个简单而有用的包装器,它为Vec&lt;u8&gt; 实现了Read,因此它允许将向量用作可读实体。

let mut file = Cursor::new(vector);

read_something(&mut file);

documentation 展示了如何使用Cursor 而不是File 来编写单元测试!

工作示例:

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

fn read_something(file: &mut impl Read) {
    let _ = file.read(&mut [0; 8]);
}

fn main() {
    let vector = vec![1, 2, 3, 4];

    let mut file = Cursor::new(vector);

    read_something(&mut file);
}

来自documentation关于std::io::Cursor

游标通常与内存缓冲区一起使用,以允许它们实现Read 和/或Write...

标准库在各种类型上实现了一些 I/O 特征,这些特征通常用作缓冲区,例如 Cursor&lt;Vec&lt;u8&gt;&gt;Cursor&lt;&amp;[u8]&gt;


切片

上面的例子也适用于 slices。在这种情况下,它将如下所示:

read_something(&mut &vector[..]);

工作示例:

use std::io::Read;

fn read_something(file: &mut impl Read) {
    let _ = file.read(&mut [0; 8]);
}

fn main() {
    let vector = vec![1, 2, 3, 4];

    read_something(&mut &vector[..]);
}

&amp;mut &amp;vector[..] 是“对切片的可变引用”(对向量部分引用的引用),所以我发现 Cursor 的显式选项更加清晰和优雅。


光标 切片

更多:如果您有一个拥有缓冲区的Cursor,并且您需要模拟例如“文件”的一部分,您可以从Cursor 获取slice 并传递给函数。

read_something(&mut &file.get_ref()[1..3]);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 2012-05-31
    • 1970-01-01
    • 2011-11-22
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多