【问题标题】:Unexpected auto deref behavior意外的自动取消引用行为
【发布时间】:2020-09-18 08:14:25
【问题描述】:

当尝试在 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() 编译失败。我想知道为什么会这样。

【问题讨论】:

  • 最小的工作代码示例会有所帮助。您可以使用rust play 进行分享。

标签: rust dereference


【解决方案1】:

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

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

现在,如果我们导入 BorrowMut 特征,测试将停止工作。这是因为BorrowMut trait 还有一个名为borrow_mut 的方法,即implemented for all types

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

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

this SO answer 中对自动取消引用的工作原理进行了最全面的说明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 2010-12-03
    • 1970-01-01
    • 2016-05-11
    相关资源
    最近更新 更多