我编写了一个简单的助手来循环在u8片中的小块(4位)。它在& u8上使用内部迭代器,本质上使步骤加倍,其中两个步骤都引用相同的底层u8,但在查看时过滤和移动比特。
我还使用Rc和RefCell创建了一个可变版本(而不是粘贴在这里),这需要在&mut u8上使用底层迭代器。不过,我希望只读版本也能与提供可变访问权限的迭代器一起工作。
我尝试过使用I: 'a + Borrow<u8>, T: Iterator<Item = I>代替硬编码的&'a u8和AsRef<u8>,但是失败了,因为随着内部字节变成非引用,借用发生在我的next()方法中,借出的值将避开它们的闭包。
允许我的Nibbler使用在&u8或&mut u8上迭代的迭代器需要什么?
pub enum Nibble<'a> {
MSB(&'a u8),
LSB(&'a u8),
}
impl Nibble<'_> {
pub fn from_u8(input: &u8) -> (Nibble, Nibble) {
let msb = Nibble::MSB(input);
let lsb = Nibble::LSB(input);
(msb, lsb)
}
pub fn get(&self) -> u8 {
match self {
Nibble::MSB(r) => (**r & 0b11110000) >> 4,
Nibble::LSB(r) => **r & 0b00001111,
}
}
}
pub struct Nibbler<'a, T> {
rest: Option<Nibble<'a>>,
inner: T,
}
impl<T> Nibbler<'_, T> {
pub fn new(inner: T) -> Self {
Nibbler { inner, rest: None }
}
}
impl<'a, T: Iterator<Item = &'a u8>> Iterator for Nibbler<'a, T> {
type Item = Nibble<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.rest.take().or_else(|| {
self.inner.next().map(|byte| {
let (msb, lsb) = Nibble::from_u8(byte);
self.rest = Some(msb);
lsb
})
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nibble_get() {
let val = 0x79;
let (msb, lsb) = Nibble::from_u8(&val);
assert_eq!(msb.get(), 7);
assert_eq!(lsb.get(), 9);
}
#[test]
fn test_nibbler() {
let t = [0x12, 0x34, 0x56, 0x78];
for (i, nibble) in Nibbler::new(t.iter()).enumerate() {
match i {
0 => assert_eq!(nibble.get(), 2),
1 => assert_eq!(nibble.get(), 1),
2 => assert_eq!(nibble.get(), 4),
3 => assert_eq!(nibble.get(), 3),
4 => assert_eq!(nibble.get(), 6),
5 => assert_eq!(nibble.get(), 5),
6 => assert_eq!(nibble.get(), 8),
7 => assert_eq!(nibble.get(), 7),
_ => {}
}
}
}
// #[test]
// fn test_nibbler_mut() {
// let t = [0x12, 0x34, 0x56, 0x78];
// for (i, nibble) in Nibbler::new(t.iter_mut()).enumerate() {
// match i {
// 0 => assert_eq!(nibble.get(), 2),
// 1 => assert_eq!(nibble.get(), 1),
// 2 => assert_eq!(nibble.get(), 4),
// 3 => assert_eq!(nibble.get(), 3),
// 4 => assert_eq!(nibble.get(), 6),
// 5 => assert_eq!(nibble.get(), 5),
// 6 => assert_eq!(nibble.get(), 8),
// 7 => assert_eq!(nibble.get(), 7),
// _ => {}
// }
// }
// }
}正如@chayim所要求的,下面是我对Borrow的尝试
use std::borrow::Borrow;
impl<'a, I: Borrow<u8> + 'a, T: Iterator<Item = I>> Iterator for Nibbler<'a, T> {
type Item = Nibble<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.rest.take().or_else(|| {
self.inner.next().map(|byte| {
let (msb, lsb) = Nibble::from_u8(byte.borrow());
self.rest = Some(msb);
lsb
})
})
}
}哪种错误
error[E0515]: cannot return value referencing function parameter `byte`
--> src/utils/nibbler2.rs:42:17
|
40 | let (msb, lsb) = Nibble::from_u8(byte.borrow());
| ------------- `byte` is borrowed here
41 | self.rest = Some(msb);
42 | lsb
| ^^^ returns a value referencing data owned by the current function发布于 2022-06-07 12:39:37
经过一段时间的努力,我终于在this answer中找到了解决方案。
pub enum Nibble<'a> {
MSB(&'a u8),
LSB(&'a u8),
}
impl Nibble<'_> {
pub fn from_u8(input: &u8) -> (Nibble, Nibble) {
let msb = Nibble::MSB(input);
let lsb = Nibble::LSB(input);
(msb, lsb)
}
pub fn get(&self) -> u8 {
match self {
Nibble::MSB(r) => (**r & 0b11110000) >> 4,
Nibble::LSB(r) => **r & 0b00001111,
}
}
}
pub struct Nibbler<'a, T> {
rest: Option<Nibble<'a>>,
inner: T,
}
impl<T> Nibbler<'_, T> {
pub fn new(inner: T) -> Self {
Nibbler { inner, rest: None }
}
}
impl<'a, T> Iterator for Nibbler<'a, T>
where
T: Iterator,
<T as Iterator>::Item: IntoNibbleRef<'a>,
{
type Item = Nibble<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.rest.take().or_else(|| {
self.inner.next().map(|byte| {
let (msb, lsb) = Nibble::from_u8(byte.into_nibble_ref());
self.rest = Some(msb);
lsb
})
})
}
}
trait IntoNibbleRef<'a> {
fn into_nibble_ref(self) -> &'a u8;
}
impl<'a> IntoNibbleRef<'a> for &'a u8 {
fn into_nibble_ref(self) -> &'a u8 {
self
}
}
impl<'a> IntoNibbleRef<'a> for &'a mut u8 {
fn into_nibble_ref(self) -> &'a u8 {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nibble_get() {
let val = 0x79;
let (msb, lsb) = Nibble::from_u8(&val);
assert_eq!(msb.get(), 7);
assert_eq!(lsb.get(), 9);
}
#[test]
fn test_nibbler() {
let t = [0x12, 0x34, 0x56, 0x78];
for (i, nibble) in Nibbler::new(t.iter()).enumerate() {
match i {
0 => assert_eq!(nibble.get(), 2),
1 => assert_eq!(nibble.get(), 1),
2 => assert_eq!(nibble.get(), 4),
3 => assert_eq!(nibble.get(), 3),
4 => assert_eq!(nibble.get(), 6),
5 => assert_eq!(nibble.get(), 5),
6 => assert_eq!(nibble.get(), 8),
7 => assert_eq!(nibble.get(), 7),
_ => {}
}
}
}
#[test]
fn test_nibbler_mut() {
let mut t = [0x12, 0x34, 0x56, 0x78];
for (i, nibble) in Nibbler::new(t.iter_mut()).enumerate() {
match i {
0 => assert_eq!(nibble.get(), 2),
1 => assert_eq!(nibble.get(), 1),
2 => assert_eq!(nibble.get(), 4),
3 => assert_eq!(nibble.get(), 3),
4 => assert_eq!(nibble.get(), 6),
5 => assert_eq!(nibble.get(), 5),
6 => assert_eq!(nibble.get(), 8),
7 => assert_eq!(nibble.get(), 7),
_ => {}
}
}
}
}您需要引入另一个可以将&u8和&mut u8转换为&u8的嵌套特性,这里称为IntoNibbleRef。
在进行了更多的实验之后,我意识到您也可以泛泛地实现这样一个特性:
impl<'a, T> Iterator for Nibbler<'a, T>
where
T: Iterator,
<T as Iterator>::Item: IntoImmutableRef<'a, u8>,
{
type Item = Nibble<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.rest.take().or_else(|| {
self.inner.next().map(|byte| {
let (msb, lsb) = Nibble::from_u8(byte.into_immutable_ref());
self.rest = Some(msb);
lsb
})
})
}
}trait IntoImmutableRef<'a, T> {
fn into_immutable_ref(self) -> &'a T;
}
impl<'a, T> IntoImmutableRef<'a, T> for &'a T {
fn into_immutable_ref(self) -> &'a T {
self
}
}
impl<'a, T> IntoImmutableRef<'a, T> for &'a mut T {
fn into_immutable_ref(self) -> &'a T {
self
}
}https://stackoverflow.com/questions/72509006
复制相似问题