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。
答案 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。