首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不能在一段代码中一次不止一次地以可变的形式借用--但在另一个非常相似的代码中却是如此。

不能在一段代码中一次不止一次地以可变的形式借用--但在另一个非常相似的代码中却是如此。
EN

Stack Overflow用户
提问于 2015-06-26 07:07:35
回答 2查看 6.1K关注 0票数 11

我有一个片段没有通过借阅检查:

代码语言:javascript
复制
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() {}
代码语言:javascript
复制
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中,而FunctionCopy)。

&'a mut self更改为其他东西没有帮助。

然而,下面的片段在精神上有点类似,被接受了:

代码语言:javascript
复制
#[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,后者通过借阅检查程序并正常运行。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-06-26 07:20:23

你掉进了一生的陷阱。将相同的生命期添加到更多的引用将更多地限制您的程序。增加更多的生命周期,并给予每个引用最小的可能寿命将允许更多的程序。正如@o11c所指出的,删除对'a生存期的限制将解决您的问题。

代码语言:javascript
复制
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插入了新的生命周期,所以在编译器中,函数的签名如下所示:

代码语言:javascript
复制
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>

永远不要使用任何生命周期,让编译器变得聪明。如果这样做失败了,不要将生命周期分散到任何地方,想想在哪里传递所有权,以及想在什么地方限制引用的生存期。

票数 9
EN

Stack Overflow用户

发布于 2015-06-26 07:20:35

您只需要删除不必要的生存期限定符就可以编译:

代码语言:javascript
复制
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

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31067031

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档