用迭代器项目进行摘要而进行的可变性
我写了一个简单的助手,在U8切片中循环绕着小吃(4位)。它使用& U8
基本上将步骤加倍,其中两个步骤都指的是相同的基础u8
,但在查看时过滤并移动位。
我还使用rc
和refcell
创建了一个可变版本(在此处粘贴),该版本需要& mut u8 u8
的基础迭代器。但是,我希望仅阅读版本也可以与可提供可变访问的迭代器一起使用。
我已经尝试使用i:'a + borrow< u8> t:iterator< item = i>
而不是硬编码&'a u8
and <代码> asref&lt; u8&gt; ,但失败了,因为内部字节成为非参考,借贷发生在我的next()
方法中。
允许我的nibbler
与迭代器配合使用>&amp; u8
或&amp; mut u8 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-friedman的要求,这是我尝试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
I've written a simple helper to loop over nibbles (4 bits) in an u8 slice. It uses an internal iterator over & u8
and essentially doubles the steps, where two steps both refer to the same underlying u8
but filter and shift the bits when viewed.
I created a mutable version as well (not pasted here) using Rc
and RefCell
, which requires an underlying iterator over &mut u8
. However I would like the read-only version to also work with iterators that provide mutable access.
I've tried using I: 'a + Borrow<u8>, T: Iterator<Item = I>
instead of the hard-coded &'a u8
and AsRef<u8>
as well, but failed because with the inner byte becoming a non-reference, the borrowing occurs in my next()
method where the borrowed values would escape their closure.
What would be required to allow my Nibbler
to work with iterators that either iterate over &u8
or &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),
// _ => {}
// }
// }
// }
}
As requested by @chayim-friedman, here's my attempt with 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
})
})
}
}
which errors with
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在努力挣扎了一段时间之后,我终于在
方案将
&amp; u8
和&amp; mut u8
转换为&amp; u8
,此处称为intonibbleref
。经过更多的实验,我意识到您也可以一般地实现这样的特征:
After struggling with this for a while, I finally found the solution in this answer:
You need to introduce another nested trait that can convert both
&u8
and&mut u8
into&u8
, here calledIntoNibbleRef
.After a little more experimenting, I realized you can also implement such a trait generically: