我有一个包含数据和最终将用于写入数据的写入器的结构。该结构包装在 RefCell
中。这是一个小复制品:
use std::cell::RefCell;
use std::io::Write;
struct Data {
string: String,
}
struct S {
data: Data,
writer: Vec<u8>,
}
fn write(s: RefCell<S>) {
let mut mut_s = s.borrow_mut();
let str = &mut_s.data.string;
mut_s.writer.write(str.as_bytes());
}
编译器生气了:
error[E0502]: cannot borrow `mut_s` as mutable because it is also borrowed as immutable
--> src\main.rs:16:5
|
15 | let str = &mut_s.data.string;
| ----- immutable borrow occurs here
16 | mut_s.writer.write(str.as_bytes());
| ^^^^^ mutable borrow occurs here
17 | }
| - immutable borrow ends here
我应该使用不同的 API 吗?
最佳答案
您可以手动调用 DerefMut
,然后保存生成的引用:
fn write(s: RefCell<S>) {
let mut mut_s = s.borrow_mut();
let mut tmp = &mut *mut_s; // Here
let str = &tmp.data.string;
tmp.writer.write(str.as_bytes());
}
或者在一行中:
fn write(s: RefCell<S>) {
let mut_s = &mut *s.borrow_mut(); // Here
let str = &mut_s.data.string;
mut_s.writer.write(str.as_bytes());
}
问题是 borrow_mut
不直接返回你的结构——它返回一个 RefMut
.通常,这是透明的,因为此结构实现了 Deref
和 DerefMut
,因此调用它的任何方法都将传递给基础类型。伪扩展代码看起来像这样:
use std::cell::RefMut;
use std::ops::{Deref, DerefMut};
fn write(s: RefCell<S>) {
let mut mut_s: RefMut<S> = s.borrow_mut();
let str = &Deref::deref(&mut_s).data.string;
DerefMut::deref_mut(&mut mut_s).writer.write(str.as_bytes());
}
Rust 不跟踪跨函数调用的字段级借用(即使是 Deref::deref
或 DerefMut::deref_mut
)。这会导致您的错误,因为在从先前的 Deref::deref
借用未完成的过程中需要调用 deref_mut
方法。
具有显式借用的扩展版本如下所示,只需调用一次 Deref::deref_mut
:
use std::cell::RefMut;
use std::ops::DerefMut;
fn write(s: RefCell<S>) {
let mut mut_s: RefMut<S> = s.borrow_mut();
let tmp: &mut S = DerefMut::deref_mut(&mut mut_s);
let str = &tmp.data.string;
tmp.writer.write(str.as_bytes());
}
然后,编译器可以跟踪从该临时值借用的两次是不相交的。
请注意,此问题并非RefCell
所独有!任何实现 DerefMut
的类型可以遇到同样的问题。以下是标准库中的一些内容:
盒子
MutexGuard
(来自Mutex
)PeekMut
(来自BinaryHeap
)RwLockWriteGuard
(来自RwLock
)字符串
Vec
-
Pin
关于rust - 尝试从包含在 RefCell 中的结构中借用 2 个字段时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58842924/