代码之家  ›  专栏  ›  技术社区  ›  Iris

使用`RefCell<T>时出现奇怪的编译时借用错误`

  •  0
  • Iris  · 技术社区  · 2 年前

    我正在使用ratatui库制作一个使用rustc 1.77.2的程序。

    我有以下代码:

    self.terminal().draw(|frame| self.render_frame(frame))?;
    

    哪里 terminal() 是用于结构的getter,该结构持有终端的实例 &self ,draw是一种在屏幕上绘制的ratatui方法。 self.render_frame takes&mut self。

    如果 航空站 返回一个 &mut Terminal ,则会导致借用错误,因此 航空站 返回一个 RefMut<Terminal> 虽然 Self 有一个 terminal 包含的字段 RefCell<Terminal ,和呼叫 self.terminal.borrow_mut() 作为的实施 航空站 .

    我的逻辑是,既然 航空站 退货 refmut ,一个不被借款检查器考虑的自有价值,并且只要 航空站 未在中使用 self.render_frame() ,不会有任何问题。

    然而,事实并非如此,因为我得到了以下错误:

    error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable
      --> src/tui.rs:75:38
       |
    75 |                 self.terminal().draw(|frame| self.render_frame(frame))?;
       |                 ---------------      ^^^^^^^ ----                      - ... and the immutable borrow might be used here, when that temporary is dropped and runs the destructor for type `RefMut<'_, ratatui::Terminal<ratatui::backend::CrosstermBackend<Stdout>>>`
       |                 |                    |       |
       |                 |                    |       second borrow occurs due to use of `self` in closure
       |                 |                    mutable borrow occurs here
       |                 immutable borrow occurs here
       |                 a temporary with access to the immutable borrow is created here ...
    

    让我困惑的是,为什么 RefMut 由借用检查器考虑,当这些规则在运行时强制执行时,表面上是 RefCell .

    具体来说,我有兴趣了解我如何使用 RefMut / RefCell 是不正确的,以及我如何修复它;因为我找不到 任何 使用时有关借用检查器错误的信息 Refcell .

    1 回复  |  直到 2 年前
        1
  •  1
  •   cdhowie    2 年前

    让我困惑的是,为什么 RefMut 由借用检查器考虑,当这些规则在运行时强制执行时,表面上是 RefCell .

    在运行时强制执行规则是 RefCell 但就其内容而言。这个 只有 内部可变类型喜欢的东西 RefCell 给你的是通过共享引用进行变异的能力。假使 RefCell ,这允许您获得 &mut T 来自 &RefCell<T> 。换句话说,这允许您“升级”共享借用( & )独家借款( &mut )但要做到这一点 你仍然需要的共享借用 RefCell .

    这反映在的签名中 RefCell::borrow_mut :

    pub fn borrow_mut(&self) -> RefMut<'_, T>
    

    如果我们取消明确取消的寿命:

    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T>
    

    所以你可以看到 RefMut 借用自 *self 这个 RefCell ). (如果没有,这意味着你可以放弃 RefCell 而你有 RefMut 指着它。这听起来不太好!)

    看起来像 render_frame &mut self ,这导致了问题: RefMut 持有共同借款 self 但是 渲染帧 想要一个 独家

    如果没有看到代码的其余部分,很难准确地说出如何解决这个问题。一种选择是 渲染帧 &self 而不是 &mut self ,在这种情况下是允许的。然而,这样做可能需要使更多此类部分使用内部可变性。

    听起来很像是从面向对象的角度来处理这个问题,而这样的设计在Rust中往往不能很好地工作。也许是任何类型 自己 这里的代表做得太多了,需要分开。

    推荐文章