Vec
sはstd::io::Write
をサポートしているため、たとえばFile
またはVec
を使用するコードを記述できます。 APIリファレンスからは、Vec
もスライスもstd::io::Read
をサポートしていないようです。
これを達成するための便利な方法はありますか?ラッパー構造体を書く必要がありますか?
これは、ファイルを読み書きする作業コードの例であり、ベクトルを読み取る必要がある1行がコメント化されています。
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`
ファイルシステムに書き込むことなく、ファイル形式のエンコーダー/デコーダーのテストを作成したいと思います。
ベクトルは_std::io::Read
_をサポートしていませんが、スライスはサポートしています。
Rust Vec
をスライスに強制できる状況もあれば、強制できない状況もあるため、ここでは混乱が生じます。
この場合、強制が適用される段階で、コンパイラは_Vec<u8>
_ しないRead
を実装することを知らないため、スライスへの明示的な強制が必要です。
問題のコードは、ベクトルがread_4_bytes(&*vec_as_file)
またはread_4_bytes(&vec_as_file[..])
のいずれかのように強制的にスライスされたときに機能します。
注意:
Read
の代わりに_&Read
_を使用していました。これにより、スライスへの参照の受け渡しが失敗しました。ただし、_&&*vec_as_file
_を渡したとは思わなかった場合を除きます。#Rust
_の@areteに感謝します!std::io::Cursor
は、Vec<u8>
の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);
}
ドキュメント からstd::io::Cursor
について:
カーソルは通常、メモリ内バッファで使用され、
Read
および/またはWrite
..を実装できるようにします。標準ライブラリは、
Cursor<Vec<u8>>
やCursor<&[u8]>
など、バッファとして一般的に使用されるさまざまなタイプにいくつかのI/O特性を実装しています。
上記の例は、スライスでも機能します。その場合、次のようになります。
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[..]);
}
&mut &vector[..]
は「スライスへの可変参照」(ベクトルの一部への参照)であるため、Cursor
を使用した明示的なオプションの方がより明確でエレガントであることがわかります。
さらに、バッファを所有するCursor
があり、たとえば「ファイル」の一部をエミュレートする必要がある場合は、slice
からCursor
を取得して、関数に渡すことができます。
read_something(&mut &file.get_ref()[1..3]);