在向函数添加memoization时,借用检查器会抱怨

时间:2018-03-20 20:17:54

标签: rust borrow-checker

我想将memoization添加到一个可能有点昂贵的函数中。我尝试在下面做一个最小的例子来证明错误。

use std::collections::{HashMap};

struct Foo {
    data: i64,
    memo: HashMap<i64, String>
}

impl Foo {
    fn new(data: i64) -> Foo {
        let memo = HashMap::new();
        Foo {data, memo}
    }

    fn f(&self, x: i64) -> String {
        (self.data + x).to_string()
    }

    fn f_cached(&mut self, x: i64) -> String {
        match self.memo.get(&x) {
            Some(result) => result.clone(),
            None => {
                let result = self.f(x);
                self.memo.insert(x, result.clone());
                result
            }
        }
    }
}

我删除下面的f_cached函数,然后编译所有内容,但缓存版本拒绝编译;我得到的错误是:

error[E0502]: cannot borrow `self.memo` as mutable because it is also borrowed as immutable
   --> src/main.rs:173:17
    |
169 |         match self.memo.get(&x) {
    |               --------- immutable borrow occurs here
...
173 |                 self.memo.insert(x, result.clone());
    |                 ^^^^^^^^^ mutable borrow occurs here
...
176 |         }
    |         - immutable borrow ends here

我尝试过基本逻辑的各种重写,例如将self.memo.get(&x)分配给变量,使用if let等等,但是所有内容都会产生相同或不同类型的错误。当然,它并没有看起来,就像代码中出现任何不安全因素一样。

1 个答案:

答案 0 :(得分:0)

虽然其他引用是正确的,但请注意,在编译器的夜间版本中,可以使用称为非词汇生命周期的功能,启用该功能后,可以使您的代码可编译:

#![feature(nll)]

use std::collections::{HashMap};

struct Foo {
    data: i64,
    memo: HashMap<i64, String>
}

impl Foo {
    fn new(data: i64) -> Foo {
        let memo = HashMap::new();
        Foo {data, memo}
    }

    fn f(&self, x: i64) -> String {
        (self.data + x).to_string()
    }

    fn f_cached(&mut self, x: i64) -> String {
        match self.memo.get(&x) {
            Some(result) => result.clone(),
            None => {
                let result = self.f(x);
                self.memo.insert(x, result.clone());
                result
            }
        }
    }
}

fn main() {}

Playground

NLL功能的跟踪问题是here。它目前正在积极开发中,并且可能在最近的将来不会稳定,但它是Rust的发展方向,如果您对使用夜间版本的编译器感到满意,那么您可以使用#![feature(nll)]