如何从Vec或切片读取(std::io::read)?

如何从Vec或切片读取(std::io::read)?,io,rust,traits,Io,Rust,Traits,Vecs支持std::io::Write,因此可以编写包含文件或Vec的代码。从API参考来看,它看起来既不支持Vec也不支持std::io::Read 有没有一个方便的方法来实现这一点?是否需要编写包装器结构 下面是一个工作代码的示例,它读取和写入一个文件,其中一行注释应该读取一个向量 use ::std::io; // Generic IO fn write_4_bytes<W>(mut file: W) -> Result<usize, io::Error>

Vec
s支持
std::io::Write
,因此可以编写包含
文件或
Vec
的代码。从API参考来看,它看起来既不支持
Vec
也不支持
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();
}
use::std::io;
//通用IO
fn写入4字节(mut文件:W)->结果
其中W:io::Write,
{
设len=file.write(b“1234”)?;
好的(len)
}
fn读取4字节(mut文件:R)->结果
其中R:io::Read,
{
让mut buf:[u8;4]=[0;4];
文件读取(&mut buf)?;
Ok(buf)
}
//特定类型
fn写入\读取\向量(){
让mut-vec_作为_文件:vec=vec::new();
{//Write
println!(“写入向量…{}”,写入4字节(&mut Vec_as_file).unwrap());
}
{//Read
//println!(“读取文件…{:?}”,读取4字节(&vec_as_文件).unwrap());
//                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//注释上面的这一行以避免错误!
}
}
fn写入\读取\文件(){
让filepath=“temp.txt”;
{//Write
让mut file_作为_file=::std::fs::file::create(filepath).expect(“打开失败”);
println!(“写入文件…{}”,写入4字节(&mut File_as_File).unwrap());
}
{//Read
让mut file_作为_file=::std::fs::file::open(filepath).expect(“打开失败”);
println!(“读取文件…{:?}”,读取4字节(&mut File_as_File).unwrap());
}
}
fn main(){
写入读取向量();
写入读取文件();
}
此操作失败,错误如下:

error[E0277]:未满足特性绑定'std::vec::vec:std::io::Read'
-->src/main.rs:29:42
|
29 | println!(“正在读取文件…{:?}”,读取4字节(&vec_as_File).unwrap());
|^^^^^^^^^^^^^^未为'std::vec::vec'实现特性'std::io::Read'`
|
=注意:`read_4_bytes'需要`

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

虽然向量不支持
std::io::Read
,但片支持

在某些情况下,Rust能够将
Vec
强制转换为切片,但在其他情况下却不能,这造成了一些混乱

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


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

  • 读取4字节(&*vec\u作为文件)
  • 读取4字节(&vec\u as\u文件[…])
  • 读取4字节(vec\u as\u file.as\u slice())

注:

  • 最初问这个问题时,我用的是
    &Read
    ,而不是
    Read
    。这使得传递对切片的引用失败,除非我传入了
    &&&vec_as_文件
    ,我认为这是不可能的
  • rust的最新版本您还可以使用
    as_slice()
    将Vec转换为切片
  • 感谢@arete on
    #rust
    找到了解决方案
std::io::游标
std::io::Cursor
是一个简单而有用的包装器,它为
Vec
实现了
Read
,因此它允许将vector用作可读实体

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

read_something(&mut 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);
}
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[..]);
}
从about
std::io::Cursor

游标通常与内存缓冲区一起使用,以允许它们执行
读取和/或
写入

标准库在常用作缓冲区的各种类型上实现了一些I/O特性,如
Cursor
Cursor


片 上述示例也适用于切片。在这种情况下,它将如下所示:

read_something(&mut &vector[..]);
工作示例:

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);
}
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[..]);
}
&mut&vector[…]
是一个“对一个切片的可变引用”(对向量一部分的引用),因此我发现使用
游标的显式选项更清晰、更优雅


光标切片 更重要的是:如果您有一个拥有缓冲区的
游标
,并且您需要模拟(例如)“文件”的一部分,那么您可以从
游标
获取一个
切片
,并传递给函数

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

我已经删除了我的答案。这个问题现在比最初提出时要大得多,提供了更多的上下文。@simon whitehead,为最初没有给出一个全面的问题表示歉意,我想我可能遗漏了一些完全不需要工作代码示例的东西。在rust的最新版本中,您还可以使用
as_slice()
Vec
转换为slice,然后使用
Read
中的方法。