tl;dr创建一些字节存储的最佳“Rust 方式”是什么,在这种情况下是 a Vec<u8>,将其存储Vec<u8>在struct可以使用键值(如 a BTreeMap<usize, &Vec<u8>>)访问的字段中,然后Vec<u8>从其他一些structs 中读取它们?
这是否可以推断为类似structs的一般良好的防锈设计,这些s 充当可使用键(偏移量、索引、文件路径等)访问的字节(Vec<u8>、[u8; 16384]、 等)的存储和缓存?usizeu32String
我正在尝试创建一个字节存储struct和impl功能:
Vec<u8>容量为 16384 的“块”中struct将分析各种Vec<u8>并可能需要存储自己对这些“块”的引用不幸的是,对于每次实现尝试,我都会遇到借用、生命周期省略、可变性、复制或其他问题的难题。
我创建了一个struct BlockReader即
Vec<u8>( Vec<u8>::with_capacity(16384)) 类型为BlockFile::seek和File::take::read_to_end)并将 16384 存储u8到一个Vec<u8>Vec<u8>内部BTreeMap类型为的引用Blocks(游乐场代码)
use std::io::Seek;
use std::io::SeekFrom;
use std::io::Read;
use std::fs::File;
use std::collections::BTreeMap;
type Block = Vec<u8>;
type Blocks<'a> = BTreeMap<usize, &'a Block>;
pub struct BlockReader<'a> {
blocks: Blocks<'a>,
file: File,
}
impl<'a> BlockReader<'a> {
/// read a "block" of 16384 `u8` at file offset
/// `offset` which is multiple of 16384
/// if the "block" at the `offset` is cached in
/// `self.blocks` then return a reference to that
/// XXX: assume `self.file` is already `open`ed file
/// handle
fn readblock(& mut self, offset: usize) -> Result<&Block, std::io::Error> {
// the data at this offset is the "cache"
// return reference to that
if self.blocks.contains_key(&offset) {
return Ok(&self.blocks[&offset]);
}
// have not read data at this offset so read
// the "block" of data from the file, store it,
// return a reference
let mut buffer = Block::with_capacity(16384);
self.file.seek(SeekFrom::Start(offset as u64))?;
self.file.read_to_end(&mut buffer);
self.blocks.insert(offset, & buffer);
Ok(&self.blocks[&offset])
}
}
Run Code Online (Sandbox Code Playgroud)
每个实现都有很多问题。例如,对BlockReader.readblocka 的两次调用struct BlockAnalyzer1就造成了无穷无尽的困难:
pub struct BlockAnalyzer1<'b> {
pub blockreader: BlockReader<'b>,
}
impl<'b> BlockAnalyzer1<'b> {
/// contrived example function
pub fn doStuff(&mut self) -> Result<bool, std::io::Error> {
let mut b: &Block;
match self.blockreader.readblock(3 * 16384) {
Ok(val) => {
b = val;
},
Err(err) => {
return Err(err);
}
}
match self.blockreader.readblock(5 * 16384) {
Ok(val) => {
b = val;
},
Err(err) => {
return Err(err);
}
}
Ok(true)
}
}
Run Code Online (Sandbox Code Playgroud)
结果是
error[E0597]: `buffer` does not live long enough
--> src/lib.rs:34:36
|
15 | impl<'a> BlockReader<'a> {
| -- lifetime `'a` defined here
...
34 | self.blocks.insert(offset, & buffer);
| ---------------------------^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `buffer` is borrowed for `'a`
35 | Ok(&self.blocks[&offset])
36 | }
| - `buffer` dropped here while still borrowed
Run Code Online (Sandbox Code Playgroud)
但是,对于这种设计的不同排列,我遇到了许多其他错误,例如我遇到的另一个错误
error[E0499]: cannot borrow `self.blockreader` as mutable more than once at a time
--> src/main.rs:543:23
|
463 | impl<'a> BlockUser1<'a> {
| ----------- lifetime `'a` defined here
...
505 | match self.blockreader.readblock(3 * 16384) {
| ---------------------------------------
| |
| first mutable borrow occurs here
| argument requires that `self.blockreader` is borrowed for `'a`
...
543 | match self.blockreader.readblock(5 * 16384) {
| ^^^^^^^^^^^^^^^^ second mutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)
在 中BlockReader,我尝试Block使用Vec<u8>, &Vec<u8>, Box<Vec<u8>>, Box<&Vec<u8>>, &Box<&Vec<u8>>,&Pin<&Box<&Vec<u8>>等对“ ”存储进行排列。但是,每个实现排列都会遇到各种与借用、生命周期和可变性有关的混淆问题。
同样,我不是在寻找特定的修复方法。我正在为这个一般问题寻找一种通常良好的面向 Rust 的设计方法:存储由 some 管理的一团字节struct,有其他struct获取对一团字节的引用(或指针等),在循环(同时可能存储新的字节块)。
Rust 专家将如何解决这个问题?
我应该如何将Vec<u8>( Block)存储在中BlockReader.blocks,并允许其他Struct人将他们自己的引用(或指针,或对指针的引用,或固定框指针等)存储到Block?
其他人是否应该struct复制或克隆 aBox<Block>或 aPin<Box<Block>>或其他东西?
会使用不同的存储,比如固定大小的数组;type Block = [u8; 16384];更容易传递引用?
是否应该给出其他Structlike 、 or 、 or或其他东西?BlockUser1&BlockBox<Block>&Pin<&Box<&Block>
同样,每个Vec<u8>( Block) 被写入一次 (during BlockReader.readblock) 并且可以被其他Structs 通过调用读取多次BlockReader.readblock,然后通过保存他们自己的引用/指针/等。到那个Block(理想情况下,也许这不理想?)。
如果它们是不可变的,您可以将Vec<u8>anRc<RefCell<...>>或简单的 a放在后面。Rc<..>
如果您需要线程安全访问,则需要使用Arc<Mutex<...>>orArc<RwLock<...>>代替。
这是代码的转换版本。(有一些拼写错误和位需要更改才能编译 - 你应该真正修复示例中的这些错误,并给我们一些几乎可以编译的东西......)你也可以在操场上看到这一点
use std::io::Seek;
use std::io::SeekFrom;
use std::io::Read;
use std::fs::File;
use std::cell::RefCell;
use std::rc::Rc;
use std::collections::BTreeMap;
type Block = Vec<u8>;
type Blocks = BTreeMap<usize, Rc<RefCell<Block>>>;
pub struct BlockReader {
blocks: Blocks,
file: File,
}
impl BlockReader {
/// read a "block" of 16384 `u8` at file offset
/// `offset` which is multiple of 16384
/// if the "block" at the `offset` is cached in
/// `self.blocks` then return a reference to that
/// XXX: assume `self.file` is already `open`ed file
/// handle
fn readblock(& mut self, offset: usize) -> Result<Rc<RefCell<Block>>,std::io::Error> {
// the data at this offset is the "cache"
// return reference to that
if self.blocks.contains_key(&offset) {
return Ok(self.blocks[&offset].clone());
}
// have not read data at this offset so read
// the "block" of data from the file, store it,
// return a reference
let mut buffer = Block::with_capacity(16384);
self.file.seek(SeekFrom::Start(offset as u64))?;
self.file.read_to_end(&mut buffer);
self.blocks.insert(offset, Rc::new(RefCell::new(buffer)));
Ok(self.blocks[&offset].clone())
}
}
pub struct BlockAnalyzer1 {
pub blockreader: BlockReader,
}
impl BlockAnalyzer1 {
/// contrived example function
pub fn doStuff(&mut self) -> Result<bool,std::io::Error> {
let mut b: Rc<RefCell<Block>>;
match self.blockreader.readblock(3 * 16384) {
Ok(val) => {
b = val;
},
Err(err) => {
return Err(err);
}
}
match self.blockreader.readblock(5 * 16384) {
Ok(val) => {
b = val;
},
Err(err) => {
return Err(err);
}
}
Ok(true)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
106 次 |
| 最近记录: |