如何根据self中hashmap的值引用更新self

时间:2017-05-23 18:08:49

标签: rust

use std::collections::HashMap;
use std::collections::hash_map::Entry::*;

struct A {
    map: HashMap<String, String>,
    i: i32
}
impl A {
    fn test(&mut self) {
        match self.map.get("abc") {
            None => {},
            Some(x) => self.trigger(&x)
        }
    }

    fn trigger(&mut self, x: &str) {
        self.i += 1;
    }
}

代码不起作用,因为self.trigger可变地借用self,而self.map.get在范围内保持self的不可变借用。

有没有办法让它发挥作用,因为我可以确保trigger我不修改self.map

我无法使trigger不可变地借用self,如Can I borrow self immutably for self.callbacks: Vec<Box<FnMut>>?

我每晚使用rustc 1.19.0。

1 个答案:

答案 0 :(得分:4)

此处的问题是借用检查程序不知道trigger仅更改self.i。借款检查员知道,它也可能会改变self.map,这是不安全的。

解决方案是告诉借阅检查器更多关于trigger更改的内容。

实现此目的的一种方法是将trigger需要可变地借用的所有内容移动到其自己的结构中,然后为该结构实现触发器:

use std::collections::HashMap;
use std::collections::hash_map::Entry::*;

struct TriggerThing {
    i: i32
}

impl TriggerThing {
    fn trigger(&mut self, _: &HashMap<String, String>, x: &str) {
        self.i += 1;
    }
}

struct A {
    map: HashMap<String, String>,
    trigger_thing: TriggerThing,
}

impl A {
    fn test(&mut self) {
        // Its fine to have a immutable borrow of self.map
        // and a mutable borrow of self.trigger_thing at the
        // same time, since borrowing self.trigger_thing does not
        // imply a mutable borrow of self.map.
        if let Some(x) = self.map.get("abc") {
            // Notice that we can still give self.trigger_thing
            // access to self.map, as long as we only
            // give it an immutable reference
            self.trigger_thing.trigger(&self.map, &x)
        }
    }
}

如果您之前没有看到过令人敬畏的if let语法,请参阅Rust Book: If Let