我可以写下面的函数f
,代码可以像我预期的那样编译:
use std::collections::HashMap;
struct A {
data: HashMap<u32, B>,
}
struct B {
val: Option<u32>,
}
impl A {
fn f(&mut self, key: u32) {
let data = &self.data[&key];
match data.val {
Some(value) => panic!("{}", value),
None => self.data.remove(&key),
};
}
}
在这里,key
首先被不可变地检出&self.data[&key]
,然后再次被可变地检出(self.data.remove(&key)
),但是编译器允许这样做,可能是因为在可变检出之后data
永远不会被使用。
然而,如果我使用RefCell
而不仅仅是一个常规的ref,我会得到一个编译时错误,即使逻辑在其他方面(看起来)是相同的:
use std::collections::HashMap;
use std::cell::RefCell;
struct A {
data: HashMap<u32, RefCell<B>>,
}
struct B {
val: Option<u32>,
}
impl A {
fn f(&mut self, key: u32) {
let data = self.data[&key].borrow();
match data.val {
Some(value) => panic!("{}", value),
None => self.data.remove(&key),
};
}
}
错误是:
error[E0502]: cannot borrow `self.data` as mutable because it is also borrowed as immutable
--> src/main.rs:17:21
|
14 | let data = self.data[&key].borrow();
| --------- immutable borrow occurs here
...
17 | None => self.data.remove(&key),
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
18 | };
19 | }
| - immutable borrow might be used here, when `data` is dropped and runs the destructor for type `Ref<'_, B>`
我的猜测是,编译器无法确定我完成了data
,因为它是一个RefCell
,因此在运行时检查,但如果是这样的话,有没有什么方法可以'检入'我借用的值,因为它不再需要?还是我唯一的选择就是让它超出范围?(对于这个小例子来说,这很好,但对于大的例子来说,这在美学上是不合适的。)
1条答案
按热度按时间whlutmcx1#
我的猜测是,编译器无法确定我完成了 data
编译器可以,但它选择不这样做,以避免更糟糕的意外。这里的具体规则是,
Drop
代码的类型的值(例如std::cell::Ref
)总是使该代码在作用域的末尾运行 *,删除时间/顺序很重要,因为它可能有副作用,所以编译器保持它的可预测性。
有没有什么方法可以'检查'的价值,我借来的,因为它不再需要?
解释一下别说了像这样修改你的
match
,它将编译:现在,编译器发现
data
不再存在,也不再借用self.data
,所以它允许您以后独占地借用self.data
。