【发布时间】:2018-03-18 19:17:17
【问题描述】:
Given 是一个结构,它包含一个带有一些字节码和一个指令指针的结构。它实现了获取、解码和执行的模式:
use std::convert::TryFrom;
/// Trait for a virtual machine.
pub struct VirtualMachine {
code: CodeMemory,
instruction_pointer: usize,
}
impl VirtualMachine {
pub fn new(byte_code: Vec<u8>) -> VirtualMachine {
VirtualMachine {
code: CodeMemory::new(byte_code),
instruction_pointer: 0,
}
}
/// Run a given program.
pub fn run(&mut self) -> Result<(), &str> {
loop {
let opcode = self.fetch();
if opcode.is_err() {
return Err(opcode.unwrap_err());
}
let instruction = self.decode(opcode.unwrap());
if instruction.is_err() {
return Err("Bad opcode!");
}
let instruction = instruction.unwrap();
if instruction == Instruction::Halt {
return Ok(());
}
self.execute(instruction);
}
}
fn fetch(&mut self) -> Result<u8, &str> {
self.code.fetch(self.instruction_pointer)
}
fn decode(&mut self, opcode: u8) -> Result<Instruction, Error> {
Instruction::try_from(opcode)
}
fn execute(&mut self, instruction: Instruction) {
self.inc_instruction_pointer();
match instruction {
Instruction::Nop => (),
Instruction::Halt => panic!("The opcode 'halt' should exit the loop before execute!"),
}
}
fn inc_instruction_pointer(&mut self) {
self.instruction_pointer += 1;
}
}
struct CodeMemory {
byte_code: Vec<u8>,
}
impl CodeMemory {
fn new(byte_code: Vec<u8>) -> CodeMemory {
CodeMemory { byte_code }
}
fn fetch(&self, index: usize) -> Result<u8, &str> {
if index < self.byte_code.len() {
Ok(self.byte_code[index])
} else {
Err("Index out of bounds!")
}
}
}
#[derive(Debug, PartialEq)]
pub enum Error {
UnknownInstruction(u8),
UnknownMnemonic(String),
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Instruction {
Nop,
// ...
Halt,
}
impl TryFrom<u8> for Instruction {
type Error = Error;
fn try_from(original: u8) -> Result<Self, Self::Error> {
match original {
0x01 => Ok(Instruction::Nop),
0x0c => Ok(Instruction::Halt),
n => Err(Error::UnknownInstruction(n)),
}
}
}
编译器抱怨:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:20:26
|
18 | pub fn run(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
19 | loop {
20 | let opcode = self.fetch();
| ^^^^ mutable borrow starts here in previous iteration of loop
...
23 | return Err(opcode.unwrap_err());
| ------------------------ returning this value requires that `*self` is borrowed for `'1`
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:26:31
|
18 | pub fn run(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
19 | loop {
20 | let opcode = self.fetch();
| ---- first mutable borrow occurs here
...
23 | return Err(opcode.unwrap_err());
| ------------------------ returning this value requires that `*self` is borrowed for `'1`
...
26 | let instruction = self.decode(opcode.unwrap());
| ^^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/lib.rs:38:13
|
18 | pub fn run(&mut self) -> Result<(), &str> {
| - let's call the lifetime of this reference `'1`
19 | loop {
20 | let opcode = self.fetch();
| ---- first mutable borrow occurs here
...
23 | return Err(opcode.unwrap_err());
| ------------------------ returning this value requires that `*self` is borrowed for `'1`
...
38 | self.execute(instruction);
| ^^^^ second mutable borrow occurs here
我想我理解编译器描述的问题,但我找不到解决方案或模式如何以安全的方式在 Rust 中实现它。是否可以在循环内改变结构字段?
我正在使用 Rust 1.34 来使用 TryFrom 特征。
【问题讨论】:
-
对不起,我从第一个示例中剥离了很多内容。整个项目有点大。
-
从示例中删除东西是好; minimal reproducible example 中的每一个字都很重要,包括“Minimal”。例如,您当前的代码有许多无法发挥作用的枚举变体。以您的示例并将其减少到仍然重现问题的最低限度,这是您向我们展示您在此处提出问题之前尝试解决自己的问题的一种方式。
-
去掉了不必要的枚举变量。
标签: rust