【问题标题】:How to implement a custom slice for a Bitvector如何为 Bitvector 实现自定义切片
【发布时间】:2021-05-27 03:42:34
【问题描述】:

我正在实现一个位向量。我的问题是 - 如何实现切片功能?这是我的代码(我在代码之后尝试过的事情):

use core::ops::Range;
use std::ops::Index;

pub struct Bitvec {
    vec: Vec<u8>,
}

impl Bitvec {
    pub fn new(capacity: usize) -> Bitvec {
        Bitvec {
            vec: Vec::with_capacity(capacity),
        }
    }

    pub fn bit_at(&self, index: usize) -> bool {
        let mask = 2u8.pow(7 - (index % 8) as u32);
        self.vec.get(index / 8).unwrap() & mask == mask
    }

    pub fn push(&mut self, val: u8) {
        self.vec.push(val);
    }
}

impl Index<usize> for Bitvec {
    type Output = bool;
    fn index(&self, index: usize) -> &Self::Output {
        match self.bit_at(index) {
            true => &true,
            false => &false,
        }
    }
}

impl Index<Range<usize> for Bitvec {
    type Output = ??;
    fn index(&self, index: Range<usize>) -> &Self::Output {
        //What should go here?
    }
}

fn main() {
    let mut bv = Bitvec::new(20);
    bv.push(0b1011_0011);
    assert_eq!(bv.bit_at(0), true);
    assert_eq!(bv.bit_at(1), false);

    assert_eq!(bv[0], true);
    assert_eq!(bv[1], false);

    let slice = bv[2..4]; //should return a slice that represents the two bits of [11]
}

Bitvec 的 Index 的 impl 应该返回什么?

我尝试过的事情:

  • 创建一个包含开始和结束的结构 BitSlice 并返回它。因为我需要让 BitSlice 持有对 Bitvec 的引用,所以我最终与借用检查器作斗争。也无法从 index(...) 函数返回 &BitSlice。

  • 让 Bitvec 拥有一个 BitSlice,但会遇到类似的问题,即 BitSlice 和 Bitvec 相互引用

  • 让 Bitvec 拥有一个选项,但也会遇到生命周期问题。

【问题讨论】:

  • 有趣的问题!实现范围索引的唯一两种类型是切片和字符串,它们都具有神奇的编译器支持,导致 &amp;[] 和 &amp;str 携带长度以及指向起点的指针。没有它,你必须返回某种类型的你自己的,但由于它必须是一个引用,你不能从index()创建和返回它。我希望一些更有经验的 Rustacean 能回答这个问题。
  • 我可以在 Bitvector 上实现一个 get_slice(&self, start:usize, end:usize) ,它返回一个新的 BitSlice 结构,它就是这样工作的。但我似乎无法使用 Index 特征来做到这一点。我想我必须实现一个智能指针来保存底层向量,然后在 Bitvector 和 BitSlice 之间共享它。
  • Rust subreddit 不错:reddit.com/r/rust/comments/4as7gx/…
  • "Index&lt;Range&gt; 对 Bitvec 的 impl 应该返回什么?"没什么,因为你不应该有。 Index 用于数据结构中已经存在并且可以引用的东西,但在这里这是不可能的,因为你不能引用值的位。无论您使用多少个智能指针,您都不能只创建一个 Bitslice 来返回,因为您不知道何时删除它。
  • 看看像 Rust 内置的 VecDeque 这样的东西,它选择使用 make_contiguous 和 as_slices 之类的方法,而不是使用 Index&lt;Range&gt;,因为内存中不存在连续切片.

标签: data-structures rust boolean slice


【解决方案1】:

像&amp;str 或&amp;[u8] 这样的切片类型是胖指针,包含指向某些数据的指针和长度。 &amp;[T] 类型是类似这样的结构的语法糖:

struct Slice<'a, T> {
    data: *const T,
    len: usize,
    _lifetime: PhantomData<&'a T>,
}

需要注意的是 ABI 不稳定,因此您不能对这些字段的顺序做出任何假设。

指针始终指向一个字节,而不是位,因此指向BitVec 切片的胖指针还需要包含切片在第一个字节内开始位置的位偏移:

pub struct BitSlice<'a> {
    offset: u8,
    len: usize,
    ptr: *const u8,
    _lifetime: PhantomData<&'a u8>,
}

你可以构造其中之一,但Index::index trait 方法返回&amp;Self::Output。无法将BitSlice&lt;'a&gt; 转换为&amp;'a [T]。


可能可以将长度和偏移量固定为单个usize,并非常小心如何访问它。 Here's a semi-complete sketch,但该实现中可能存在健全性漏洞。当然,如果你是 Rust 初学者,你不应该尝试它!

【讨论】:

  • 我认为它确实有效。限制是切片的长度。对于 64 位系统来说没问题,但在 16 位系统上,长度只有 8 位,这是相当严格的。
猜你喜欢
  • 2023-03-29
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-27
  • 2017-03-29
相关资源
最近更新 更多