意外的自动解引用行为

6

当我试图在 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()无法编译通过。我想知道为什么会出现这种情况。


1
提供一个最小可行的代码示例会非常有帮助。你可以使用 Rust Play 来分享它。 - S.R
1个回答

8
您需要调用的方法是 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 回答中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接