我有一个代码片段,它无法通过借用检查器:
use std::collections::HashMap;
enum Error {
FunctionNotFound,
}
#[derive(Copy, Clone)]
struct Function<'a> {
name: &'a str,
code: &'a [u32],
}
struct Context<'a> {
program: HashMap<&'a str, Function<'a>>,
call_stack: Vec<Function<'a>>,
}
impl<'a> Context<'a> {
fn get_function(&'a mut self, fun_name: &'a str) -> Result<Function<'a>, Error> {
self.program
.get(fun_name)
.map(|f| *f)
.ok_or(Error::FunctionNotFound)
}
fn call(&'a mut self, fun_name: &'a str) -> Result<(), Error> {
let fun = try!(self.get_function(fun_name));
self.call_stack.push(fun);
Ok(())
}
}
fn main() {}
error[E0499]: cannot borrow `self.call_stack` as mutable more than once at a time
--> src/main.rs:29:9
|
27 | let fun = try!(self.get_function(fun_name));
| ---- first mutable borrow occurs here
28 |
29 | self.call_stack.push(fun);
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
...
32 | }
| - first borrow ends here
我的直觉是问题与HashMap
返回数据结构内部的None
或值的引用有关。但我不希望这样:我的意图是self.get_function
应该返回存储值的字节副本或错误(这就是我加上 .map(|f| *f)
和 Function
是 Copy
的原因)。
将&'a mut self
更改为其他内容并没有帮助。
然而,下面的代码片段在精神上有些相似,但被接受:
#[derive(Debug)]
enum Error {
StackUnderflow,
}
struct Context {
stack: Vec<u32>,
}
impl Context {
fn pop(&mut self) -> Result<u32, Error> {
self.stack.pop().ok_or(Error::StackUnderflow)
}
fn add(&mut self) -> Result<(), Error> {
let a = try!(self.pop());
let b = try!(self.pop());
self.stack.push(a + b);
Ok(())
}
}
fn main() {
let mut a = Context { stack: vec![1, 2] };
a.add().unwrap();
println!("{:?}", a.stack);
}
现在我感到困惑。第一个代码片段有什么问题?为什么第二个没有这个问题?
这些片段是更大的一段代码的一部分。为了提供更多的上下文,这里在 Rust Playground 上展示了一个包含有错误代码的更完整的示例,而这里则展示了一个更早版本的示例,其中没有使用 HashMap
。
fun_name
不应该有任何生命周期。 - o11c