有没有一种方法可以使用地图中某个元素的值来更新另一个没有内部可变性的元素?

时间:2019-01-08 15:12:03

标签: rust borrow-checker

我正在尝试从同一地图中的元素(A)中查找BTreeMap中元素(B)的值,然后将A的值与B的值进行突变

我知道我可以使用RefCell来避免“不能借用X是不可变的,因为X也是借来的,因为X是可变的”,但是我想知道是否有一种更惯用的,安全的方法来做到这一点

我已经考虑过尝试存储指向其他元素的指针,但这是行不通的,因为元素的存储位置会随着向BTreeMap添加元素而移动,因此这是不安全和错误的。 / p>

是否有更好的方法来处理这种模式?

初始尝试

use std::collections::BTreeMap;

struct Map(BTreeMap<String, Foo>);

impl Map {
    fn new() -> Self {
        Map(BTreeMap::new())
    }

    fn calc_node(&mut self, name: &str) {
        self.0.get_mut(name).unwrap().calc_value(self)
    }
}

struct Foo {
    name: String,
    v: i32,

    lookup: String,
}

impl Foo {
    fn new(name: String, value: i32, lookup: String) -> Self {
        Self {
            name,
            v: value,
            lookup,
        }
    }

    fn calc_value(&mut self, map: &Map) {
        self.v = map.0.get(&self.lookup).unwrap().v * 2 // really what I'm trying to do
    }
}

fn main() {
    let mut map = Map::new();

    map.0.insert(
        "a".to_string(),
        Foo::new("a".to_string(), 1, "b".to_string()),
    );
    map.0.insert(
        "b".to_string(),
        Foo::new("b".to_string(), 2, "a".to_string()),
    );

    println!("{:?}", map.0.get("a").unwrap().v);
    map.calc_node("a");
    println!("{:?}", map.0.get("a").unwrap().v);
}
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/main.rs:11:50
   |
11 |         self.0.get_mut(name).unwrap().calc_value(self)
   |         ------                        ---------- ^^^^ immutable borrow occurs here
   |         |                             |
   |         |                             mutable borrow later used by call
   |         mutable borrow occurs here

使用RefCell

use std::cell::RefCell;
use std::collections::BTreeMap;

struct Map(BTreeMap<String, RefCell<Foo>>);

impl Map {
    fn new() -> Self {
        Map(BTreeMap::new())
    }

    fn calc_node(&self, name: &str) {
        self.0.get(name).unwrap().borrow_mut().calc_value(self)
    }
}

struct Foo {
    name: String,
    v: i32,

    lookup: String,
}

impl Foo {
    fn new(name: String, value: i32, lookup: String) -> Self {
        Self {
            name,
            v: value,
            lookup,
        }
    }

    fn calc_value(&mut self, map: &Map) {
        self.v = map.0.get(&self.lookup).unwrap().borrow().v * 2
    }
}

fn main() {
    let mut map = Map::new();

    map.0.insert(
        "a".to_string(),
        RefCell::new(Foo::new("a".to_string(), 1, "b".to_string())),
    );
    map.0.insert(
        "b".to_string(),
        RefCell::new(Foo::new("b".to_string(), 2, "a".to_string())),
    );

    println!("{:?}", map.0.get("a").unwrap().borrow().v);
    map.calc_node("a");
    println!("{:?}", map.0.get("a").unwrap().borrow().v);
}

我得到正确的结果:

1
4

RefCell具有运行时成本,理想情况下,我希望能够尽快访问引用的元素。

0 个答案:

没有答案