我正在寻找一种方法来解决缺乏polonius问题在这种特定情况下。据我目前的理解,其他答案似乎不适用。
我有两个结构,
SourceBytes<S>
和SourceChars
。前者是解耦的,但后者与前者严重耦合。 SourceBytes<S>
应由任何 S: Iterator<Item = u8>
构造,并且 SourceChars
应由相同的 S: Iterator<Item = u8>
构造。
这就是每个的定义:
#[derive(Clone, Debug)]
pub struct SourceBytes<S>
where
S: Iterator<Item = u8>,
{
iter: S,
buffer: Vec<S::Item>,
}
#[derive(Clone, Debug)]
pub struct SourceChars<S>(S)
where
S: Iterator<Item = u8>;
SourceBytes<S>
的目的是抽象S
,以便每个S::Item
可以被缓冲,并且可以不可变地读取,而不需要从迭代器中获取/弹出项目。看起来像这样:
impl<S> Iterator for SourceBytes<S>
where
S: Iterator<Item = u8>,
{
type Item = S::Item;
fn next(&mut self) -> Option<Self::Item> {
self.buffer.pop().or_else(|| self.iter.next())
}
}
这工作正常,缓冲区的处理方式如下:
impl<S> SourceBytes<S>
where
S: Iterator<Item = u8>,
{
// pub fn new<I>(iter: I) -> Self
// where
// I: IntoIterator<Item = S::Item, IntoIter = S>,
// {
// Self {
// iter: iter.into_iter(),
// buffer: Vec::new(),
// }
// }
fn buffer(&mut self, count: usize) -> Option<&[u8]> {
if self.buffer.len() < count {
self.buffer
.extend(self.iter.by_ref().take(count - self.buffer.len()));
}
self.buffer.get(0..count)
}
}
这样每次调用
SourceBytes<S>::buffer
时,都会从S
中取出物品并推送到buffer
。每次调用 <SourceBytes as Iterator>::next
时,都会首先从 self.buffer
获取,然后从 self.iter
获取,其中后一个字段的类型为 S
。
现在,
SourceChars<S>
的目的是提供一个Iterator
接口来从self.0
(即S
)读取字节,直到找到有效的UTF-8char
,然后返回它:
impl<S> Iterator for SourceChars<S>
where
S: Iterator<Item = u8>,
{
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
let mut buf = [0; 4];
// A single character can be at most 4 bytes.
for (i, byte) in self.0.by_ref().take(4).enumerate() {
buf[i] = byte;
if let Ok(slice) = std::str::from_utf8(&buf[..=i]) {
return slice.chars().next();
}
}
None
}
}
这也很好用。
现在,我还希望为
impl
提供一个SourceChars<&mut SourceBytes<S>>
,这样SourceChars
就可以依赖于self.0
提供的缓冲区(在这种情况下,就是&mut SourceBytes<S>
)。
impl<S> SourceChars<&mut SourceBytes<S>>
where
S: Iterator<Item = u8>,
{
fn buffer(&mut self, count: usize) -> Option<&str> {
// let mut src = self.0.by_ref();
for byte_count in 0.. {
let Some(buf) = self.0.buffer(byte_count) else {
return None;
};
if let Ok(slice) = std::str::from_utf8(buf) {
if slice.chars().count() >= count {
return Some(slice);
}
}
}
unreachable!()
}
}
这个
SourceChars<&mut SourceBytes<S>>::buffer
依赖于SourceBytes<S>::buffer
来实际缓冲字节,但SourceChars
充当包装器,将迭代器S
的解释从字节更改为char
s。
问题在于
self.0
不能多次可变借用,并且在循环中,引用 &mut self.0
似乎不会被编译器删除。
如何以
SourceChars
依赖于 SourceBytes::buffer
的方式实现此操作,而不会遇到此编译器错误?
error[E0499]: cannot borrow `*self.0` as mutable more than once at a time
--> src/parser/iter.rs:122:29
|
119 | fn buffer(&mut self, count: usize) -> Option<&str> {
| - let's call the lifetime of this reference `'1`
...
122 | let Some(buf) = self.0.buffer(byte_count) else {
| ^^^^^^ `*self.0` was mutably borrowed here in the previous iteration of the loop
...
127 | return Some(slice);
| ----------- returning this value requires that `*self.0` is borrowed for `'1`
解决方法与所有 Polonius 问题一样:重复计算。虽然效率较低,但确实有效。
impl<S> SourceChars<&mut SourceBytes<S>>
where
S: Iterator<Item = u8>,
{
fn buffer(&mut self, count: usize) -> Option<&str> {
// let mut src = self.0.by_ref();
for byte_count in 0.. {
let Some(buf) = self.0.buffer(byte_count) else {
return None;
};
if let Ok(slice) = std::str::from_utf8(buf) {
if slice.chars().count() >= count {
return Some(std::str::from_utf8(self.0.buffer(byte_count).unwrap()).unwrap());
}
}
}
unreachable!()
}
}