我必须迭代键,在HashMap中按键查找值,可能会在找到的 struct 中作为值进行一些繁重的计算(lazy=>mutate the struct),然后缓存并以Rust的形式返回它.

我收到以下错误消息:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:25:26
   |
23 |     fn it(&mut self) -> Option<&Box<Calculation>> {
   |           - let's call the lifetime of this reference `'1`
24 |         for key in vec!["1","2","3"] {
25 |             let result = self.find(&key.to_owned());
   |                          ^^^^ `*self` was mutably borrowed here in the previous iteration of the loop
...
28 |                 return result
   |                        ------ returning this value requires that `*self` is borrowed for `'1`

这是code in playground美元.

use std::collections::HashMap;

struct Calculation {
    value: Option<i32>
}

struct Struct {
    items: HashMap<String, Box<Calculation>> // cache
}

impl Struct {
    fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
        None // find, create, and/or calculate items
    }

    fn it(&mut self) -> Option<&Box<Calculation>> {
        for key in vec!["1","2","3"] {
            let result = self.find(&key.to_owned());
            if result.is_some() {
                return result
            }
        }
        None
    }
}
  • 我无法避免循环,因为我必须判断多个键
  • 我必须使其可变(self和 struct ),因为可能的计算会改变它

有没有关于如何改变设计的建议(因为Rust 迫使人们以一种有意义的不同方式思考)或解决它的建议?

另外,代码还有一些其他问题,但是让我们先把问题分开,解决这个问题.

推荐答案

不能使用exclusive访问进行缓存.你不能像对待通用指针一样对待 rust 迹引用(顺便说一句:&String&Box<T>是双间接的, rust 迹非常单一.临时borrow &str&T).

&mut self不仅意味着可变,还意味着exclusive和可变,因此缓存只支持返回一个项,因为它返回的引用必须在其存在的时间内保持self"锁定".

你需要让借钱人相信,下次你打电话时,find元返还的东西不会突然消失.目前没有这样的保证,因为接口不会阻止您调用例如items.clear()(borrow 判断器判断函数的接口允许什么,而不是函数实际做什么).

你可以使用Rc,或者使用一个装有a memory pool/arena的 crate .

struct Struct {
   items: HashMap<String, Rc<Calculation>>,
}

fn find(&mut self, key: &str) -> Rc<Calculation> 

通过这种方式,如果你克隆了Rc,它将独立于缓存而生存多久.

你也可以通过内部的易变性使它变得更好.

struct Struct {
   items: RefCell<HashMap<…
}

这将允许您的memoizing find方法使用共享借阅,而不是独占借阅:

fn find(&self, key: &str) -> …

对于方法的调用者来说,这更容易使用.

Rust相关问答推荐

按下按钮时如何在服务器中创建文件并在本地下载?

rust 蚀将动力特性浇到混凝土 struct 上是行不通的

如何对字符串引用的引用向量进行排序,而不是对最外层的引用进行排序?

如何仅使用http机箱发送http请求?

如果成员都实现特征,是否在多态集合上实现部分重叠的特征?

告诉Rust编译器返回值不包含构造函数中提供的引用

在文件链实施中绕过borrow 判断器

为什么HashMap::get和HashMap::entry使用不同类型的密钥?

结果流到 Vec 的结果:如何避免多个into_iter和collect?

如何使用 Bincode 在 Rust 中序列化 Enum,同时保留 Enum 判别式而不是索引?

Rust 中的生命周期:borrow 的 mut 数据

当我不满足特征界限时会发生什么?

当我在 struct 中存储异步函数时,为什么它需要生命周期

在 Rust 中为泛型 struct 编写一次特征绑定

意外的正则表达式模式匹配

为什么我可以在没有生命周期问题的情况下内联调用 iter 和 collect?

如何从 many0 传播 Nom 失败上下文?

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?

如何在 Rust 的内置函数上实现特征?

为什么 `ref` 会导致此示例*取消引用*一个字段?