如何解决向前和向后跳跃的迭代器多次可变地借用
我正在写一个虚拟机,它可以一条一条地执行指令,也可以向前和向后跳跃。
例如,如果它有一个指令列表 [A,>B,C,D]
并且当前位于指令 B
。向前跳 2 将跳过 2 条指令(B
和 C
)[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);
}
}
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。