当尝试在 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()
。
然而,a
是Rc
而不是RefCell
,所以它没有borrow_mut
方法。这就是自动取消引用进入图片的地方。由于Rc<RefCell<T>>
实现了Deref
特征,因此可以在方法调用时自动取消引用到&RefCell<T>
,这正是第一次测试中发生的情况。
现在,如果我们导入BorrowMut
特征,测试将停止工作。这是因为BorrowMut
特征也有一个名为borrow_mut
的方法,该方法适用于所有类型:
impl<T: ?Sized> BorrowMut<T> for T { ... }
这意味着现在有一个可用于Rc
的borrow_mut
方法,因此不会发生自动取消引用,并且我们的代码调用了错误的方法。
关于自动取消引用如何工作的最全面的解释是在这个 SO 答案中。