在循环中调用使用 `&mut self.0` 的函数 (E0499)

问题描述 投票:0回答:1

我正在寻找一种方法来解决缺乏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-8
char
,然后返回它:

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`
rust reference lifetime mutable
1个回答
0
投票

解决方法与所有 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!()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.