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

问题描述 投票:0回答:1

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

我有以下代码:

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

其中

terminal()
是保存接受
&self
的终端实例的结构体的 getter,draw 是绘制到屏幕的ratatui 方法。
self.render_frame
需要 &mut self。

如果

terminal()
返回
&mut Terminal
,则会导致借用错误,因此
terminal()
返回
RefMut<Terminal>
,而
Self
有一个
terminal
字段,其中包含
RefCell<Terminal
,并调用
self.terminal.borrow_mut() 
作为
terminal()
的实施。

我的逻辑是,由于

terminal()
返回
refmut
,一个自有值,借用检查器不会考虑该值,并且只要
terminal()
不用于
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 时找不到
任何
有关借用检查器错误的信息。

rust borrow-checker
1个回答
0
投票

令我困惑的是,为什么借用检查器会考虑

RefMut
,而在运行时执行的这些规则表面上就是
RefCell
的全部要点。

这是正确的,但您仍然需要共享借用才能使用它。像RefCell这样的内部可变性类型给你带来的

唯一
的事情是通过共享引用进行变异的能力。对于
RefCell
,这允许您从
&mut T
获得
&RefCell<T>
。换句话说,这允许您将共享借用 (
&
)“升级”为独占借用 (
&mut
),但要做到这一点您仍然需要
RefCell
的共享借用。

看起来

render_frame
需要
&mut self
,这会导致问题:
RefMut
借用于
self
,但
render_frame
想要一个 独占 引用。

在看不到其余代码的情况下,很难确切地说出如何解决这个问题。一种选择是让

render_frame
采用
&self
而不是
&mut self
,这在本例中是允许的。但是,这样做可能需要您使更多此类部分使用内部可变性。

听起来很像你是从面向对象的角度来解决这个问题的,而这样的设计在 Rust 中往往效果不佳。也许这里

self
代表的任何类型都做得太多,需要分开。

© www.soinside.com 2019 - 2024. All rights reserved.