gpt4 book ai didi

Rust 设计存储结构和只读结构用户的方法

转载 作者:行者123 更新时间:2023-12-04 11:29:19 25 4
gpt4 key购买 nike

tl;博士 创建一些字节存储的最佳“Rust 方式”是什么,在这种情况下是 Vec<u8> ,存储该 Vec<u8>struct可以使用键值访问的字段(例如 BTreeMap<usize, &Vec<u8>> ),然后读取这些 Vec<u8>来自其他一些 struct ?
这可以外推到类似的一般良好的防 rust 设计struct s 充当字节块( Vec<u8>[u8; 16384] 等)的存储和缓存,可通过键(usize 偏移量、u32 索引、String 文件路径等)访问?
目标
我正在尝试创建一个字节存储 structimpl功能:

  • 将按需从磁盘读取的 16384 字节存储到 Vec<u8> 的“块”中容量 16384
  • 其他 struct会分析各种Vec<u8>并且可能需要存储自己对这些“块”的引用
  • 高效:在内存中只有一个“块”的副本,避免不必要的复制、克隆等。

  • 不幸的是,对于每次实现尝试,我都会遇到借用、生命周期省略、可变性、复制或其他问题的难题。
    简化代码示例
    我创建了一个 struct BlockReader
  • 创建一个 Vec<u8> ( Vec<u8>::with_capacity(16384) ) 输入为 Block
  • 从文件中读取(使用 File::seekFile::take::read_to_end )并存储 u8 的 16384成Vec<u8>
  • 存储对 Vec<u8> 的引用内BTreeMap输入为 Blocks

  • ( playground code )
    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])
    }
    }
    用例问题示例
    每个实现都有很多问题。例如,两次调用 BlockReader.readblock来自 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)
    }
    }
    结果是
    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
    但是,对于这种设计的不同排列,我遇到了许多其他错误,例如我遇到的另一个错误
    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
    BlockReader ,我已经尝试使用 Block 对“ Vec<u8> ”存储进行排列, &Vec<u8> , Box<Vec<u8>> , Box<&Vec<u8>> , &Box<&Vec<u8>> , &Pin<&Box<&Vec<u8>>等等。然而,每个实现排列都会遇到各种与借用、生命周期和可变性相关的混淆问题。
    同样,我不是在寻找特定的修复方法。我正在为这个普遍问题寻找一种普遍良好的面向 Rust 的设计方法:存储由一些 struct 管理的字节块, 还有其他 struct获取对字节块的引用(或指针等),在循环中读取该字节块(同时可能存储新的字节块)。
    Rust 专家的问题
    Rust 专家将如何解决这个问题?
    我应该如何存放 Vec<u8> ( Block ) 在 BlockReader.blocks ,还允许其他 Struct将他们自己的引用(或指针,或对指针的引用,或固定框指针等)存储到 Block ?
    应对方 struct s 复制或克隆 Box<Block>Pin<Box<Block>>或者是其他东西?
    会使用不同的存储,比如固定大小的数组; type Block = [u8; 16384];更容易传递引用?
    应其他 Struct喜欢 BlockUser1给予 &Block , 或 Box<Block> , 或 &Pin<&Box<&Block> , 或者是其他东西?
    再次,每个 Vec<u8> ( Block ) 被写入一次(在 BlockReader.readblock 期间)并且可以被其他 Struct 多次读取s 调用 BlockReader.readblock后来通过保存他们自己的引用/指针/等。到那个 Block (理想情况下,也许这不理想?)。

    最佳答案

    你可以把Vec<u8>Rc<RefCell<...>> 后面或者只是一个 Rc<..>如果它们是不可变的。
    如果您需要线程安全访问,则需要使用 Arc<Mutex<...>>Arc<RwLock<...>>反而。
    这是您的代码的转换版本。 (有一些拼写错误和位需要更改才能编译 - 你应该在你的例子中真正修复这些,并给我们一些几乎可以编译的东西......)
    您也可以在 playground 中看到这一点。

    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)
    }
    }

    关于Rust 设计存储结构和只读结构用户的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68991015/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com