Rust 向前和向后跳跃的迭代器。多次易变地借款
我正在编写一个虚拟机,它可以一个接一个地执行指令,还可以向前和向后跳转 例如,如果它有一个指令列表Rust 向前和向后跳跃的迭代器。多次易变地借款,rust,Rust,我正在编写一个虚拟机,它可以一个接一个地执行指令,还可以向前和向后跳转 例如,如果它有一个指令列表[a、>B、C、D],并且当前位于指令B。向前跳2将跳过2条指令(B和C)[A,B,C,>D]。按1向后跳应该只跳过B[>A,B,C,D] 这就是我实现迭代器的方式 impl{ 输入Item=&'a指令; fn下一步(&mut self)->选项{ 如果self.ip选项{ 如果self.ip选项{ 如果self.ip
[a、>B、C、D]
,并且当前位于指令B
。向前跳2将跳过2条指令(B
和C
)[A,B,C,>D]
。按1向后跳应该只跳过B
[>A,B,C,D]
这就是我实现迭代器的方式
impl{
输入Item=&'a指令;
fn下一步(&mut self)->选项{
如果self.ip
读取器
存储当前指令的索引,并将其向后跳转(2)递减2
以下是我尝试使用它的方式:
while let Some(指令)=reader.next(){
如果指令==&指令::添加{
读取器。向后跳转(2);
持续
}
}
但它不起作用,因为我不断地借用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
您能为这个问题提出一个解决方案吗?一个解决方案是不使用
迭代器
特性,而是使用类似迭代器的结构,该结构将封装ip
光标,而不是读卡器,其next
函数将读卡器作为参数
它看起来像这样:
#[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
}
}
}
#[派生(默认)]
结构VmIterator{
ip:usize,
}
impl虚拟迭代器{
pub fn next(&mut self,chunk:&Reader)->选项{
如果self.ip
这将是安全和干净的,但会阻止一些迭代器模式
如果不需要将读卡器和迭代分开,还可以将ip游标直接存储在读卡器中 下面是第二个解决方案的示例:
#[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);
}
}
#[派生(调试、默认、克隆)]
结构指令{}
结构读取器{
发布fn新信息(来源:&[说明]->Self{
自{源,c:0}
}
发布fn说明(&M自我){
自我评价c-=2;
}
}
恳求{
输入项目=&的指令;
fn下一步(&mut self)->选项{
设c=self.c;
如果c
请注意,尽管它仍然是一个迭代器,但如果在迭代过程中进行了变异,则借用检查器将禁止某些迭代器构造,因此,当let some(c)=r.next()时,显式的
{
解决方案是不使用迭代器
特性,而是使用类似迭代器的结构,该结构将封装ip
光标,但不封装读取器,其next
函数将读取器作为参数
它看起来像这样:
#[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
}
}
}
#[派生(默认)]
结构VmIterator{
ip:usize,
}
impl虚拟迭代器{
pub fn next(&mut self,chunk:&Reader)->选项{
如果self.ip
这将是安全和干净的,但会阻止一些迭代器模式
如果不需要将读卡器和迭代分开,还可以将ip游标直接存储在读卡器中 下面是第二个解决方案的示例:
#[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);
}
}
#[派生(调试、默认、克隆)]
结构指令{}
结构读取器{
发布fn新信息(来源:&[说明]->Self{
自{源,c:0}
}
发布fn说明(&M自我){
自我评价c-=2;
}
}
恳求{
输入项目=&的指令;
fn下一步(&mut self)->选项{
设c=self.c;
如果c
请注意,尽管它仍然是一个迭代器,但如果在迭代过程中进行了变异,则借用检查器将禁止某些迭代器构造,因此,当let some(c)=r.next()时,显式的
{
将注释移动到您的答案将注释移动到您的答案谢谢!但是如果我们放弃迭代器模式,那么在封装ip
字段的同时,它是否可以在没有迭代器的情况下实现?我问这个问题是因为这个解决方案产生了两个实体:Reader
和iterator
似乎很麻烦:)新的“迭代器”只是ip域,在内存中的位置不会比usize更大,它只是增加了类型安全性。好吧,我只是问的不是性能和优化,而是软件架构,因为现在代码库将有2个实体。你认为可以用1个实体完成吗?取决于你的用例,但没有问题如果只有一个可能的读取,则在原始结构中使用reading\u index
。在一般情况下,分离数据和迭代会更灵活一些。但是我是否能够对