我有一个片段没有通过借阅检查:
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)放在Copy中,而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);
}现在我糊涂了。第一个片段有什么问题?为什么不发生在第二次?
这些代码片段是更大代码块的一部分。为了提供更多的上下文,铁锈游乐场上的这个展示了一个包含错误代码的更完整的示例,以及HashMap,后者通过借阅检查程序并正常运行。
发布于 2015-06-26 07:20:23
你掉进了一生的陷阱。将相同的生命期添加到更多的引用将更多地限制您的程序。增加更多的生命周期,并给予每个引用最小的可能寿命将允许更多的程序。正如@o11c所指出的,删除对'a生存期的限制将解决您的问题。
impl<'a> Context<'a> {
fn get_function(&mut self, fun_name: &str) -> Result<Function<'a>, Error> {
self.program
.get(fun_name)
.map(|f| *f)
.ok_or(Error::FunctionNotFound)
}
fn call(&mut self, fun_name: &str) -> Result<(), Error> {
let fun = try!(self.get_function(fun_name));
self.call_stack.push(fun);
Ok(())
}
}这是因为Rust插入了新的生命周期,所以在编译器中,函数的签名如下所示:
fn get_function<'b>(&'b mut self, fun_name: &'b str) -> Result<Function<'a>, Error>
fn call<'b>(&'b mut self, fun_name: &'b str) -> Result<(), Error>永远不要使用任何生命周期,让编译器变得聪明。如果这样做失败了,不要将生命周期分散到任何地方,想想在哪里传递所有权,以及想在什么地方限制引用的生存期。
发布于 2015-06-26 07:20:35
您只需要删除不必要的生存期限定符就可以编译:
fn get_function(&mut self, fun_name: &str) -> Result<Function<'a>, Error> { ... }
fn call(&mut self, fun_name: &str) -> Result<(), Error> { ... }您的问题是,您将&mut self的生存期与存储在其中的值(Function<'a>)的生存期绑定在一起,这在大多数情况下是不必要的。对于get_function()定义中存在的这个依赖项,编译器必须假设调用self.get_function(...)的结果借用了self,因此它禁止您再次借用它。
&str参数的生存期也是不必要的--它只是无缘无故地限制了可能的参数值集。您的键可以是具有任意生存期的字符串,而不仅仅是'a。
https://stackoverflow.com/questions/31067031
复制相似问题