向前和向后跳跃的迭代器多次可变地借用

问题描述

我正在写一个虚拟机,它可以一条一条地执行指令,也可以向前和向后跳跃。

例如,如果它有一个指令列表 [A,>B,C,D] 并且当前位于指令 B。向前跳 2 将跳过 2 条指令(BC[A,B,>D]。跳回 1 应该只跳过 B [>A,D]

这就是我实现迭代器的方式

impl <'a> Iterator for VmReader<'a> {
    type Item = &'a Instruction;

    fn next(&mut self) -> Option<Self::Item> {
        if self.ip < self.chunk.code.len() {
            let instruction: &'a Instruction = &self.chunk.code[self.ip];
            self.ip += 1;
            Some(instruction)
        } else {
            None
        }
    }
}

reader 存储当前指令的索引,jump_backward(2) 将其减 2。

这是我尝试使用它的方式:

while let Some(instruction) = reader.next() {
    if instruction == &Instruction::Add {
        reader.jump_backward(2);
        continue;
    }
}

但它不起作用,因为我将 reader 可变地借用了两次:

error[E0499]: cannot borrow `reader` as mutable more than once at a time
   --> src/vmm/vm_reader.rs:99:39
    |
99  |         while let Some(instruction) = reader.next() {
    |                                       ^^^^^^
    |                                       |
    |                                       second mutable borrow occurs here
    |                                       first borrow later used here
100 |             if instruction == &Instruction::Add {
101 |                 reader.jump_backward(2);
    |                 ------ first mutable borrow occurs here

你能提出解决这个问题的方法吗?

解决方法

一个解决方案是不使用 docker-compose.yml 特征,而是使用类似迭代器的结构,该结构将包装 Iterator 游标但不包装读取器,其 ip 函数将读取器作为论证。

它看起来像这样:

next

这将是安全和干净的,但会阻止某些迭代器模式。


如果不需要将Reader和迭代分开,也可以直接将ip游标存储在Reader中。

这是第二种解决方案的示例:

#[derive(Default)]
struct VmIterator {
     ip: usize,}
impl VmIterator {
    pub fn next(&mut self,chunk: &Reader) -> Option<&Instruction> {
        if self.ip < chunk.code.len() {
            let instruction: &'a Instruction = &self.chunk.code[self.ip];
            self.ip += 1;
            Some(instruction)
        } else {
            None
        }
    }
}

请注意,虽然它仍然是一个迭代器,但如果在迭代时发生变异,借用检查器将禁止某些迭代器构造,因此显式 #[derive(Debug,Default,Clone)] struct Instruction {} struct Reader<'s> { source: &'s[Instruction],c: usize,} impl<'s> Reader<'s> { pub fn new(source: &'s[Instruction]) -> Self { Self { source,c: 0 } } pub fn decr(&mut self) { self.c -= 2; } } impl<'s> Iterator for Reader<'s> { type Item = &'s Instruction; fn next(&mut self) -> Option<Self::Item> { let c = self.c; if c < self.source.len() { self.c += 1; self.source.get(c) } else { None } } } fn main() { let instructions = vec![Instruction::default(); 10]; let mut r = Reader::new(&instructions); let mut i = 0; while let Some(c) = r.next() { if i%3 == 2 { r.decr(); } i += 1; dbg!(c); } }