意外的自动取消引用行为



当尝试在 rust 中插入双链表时,我发现以下意外错误

if let Some(link) = self.tail.take() {
let x = link.borrow_mut();
link.borrow_mut().next = Some(node.clone());
} else { ... }

这里链接被推断为Rc<RefCell<Node<..>>>,编译器说:

不能借用不可变的局部变量link可变变量。

尝试后,我想当use std::borrow::BorrowMut时,会发生错误。

// compiles
fn test1() {
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}
// doesn't compile
fn test2() {
use std::borrow::BorrowMut; // inserted this import!
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}

此处test2()无法编译。我想知道为什么它以这种方式工作。

你要调用的是方法RefCell::borrow_mut()

然而,aRc而不是RefCell,所以它没有borrow_mut方法。这就是自动取消引用进入图片的地方。由于Rc<RefCell<T>>实现了Deref特征,因此可以在方法调用时自动取消引用到&RefCell<T>,这正是第一次测试中发生的情况。

现在,如果我们导入BorrowMut特征,测试将停止工作。这是因为BorrowMut特征也有一个名为borrow_mut的方法,该方法适用于所有类型:

impl<T: ?Sized> BorrowMut<T> for T { ... }

这意味着现在有一个可用于Rcborrow_mut方法,因此不会发生自动取消引用,并且我们的代码调用了错误的方法。

关于自动取消引用如何工作的最全面的解释是在这个 SO 答案中。

最新更新