An error occurred while trying to borrow 2 fields from a structure wrapped in RefCell

I have a structure that contains both data and records, which will ultimately be used to write data. The structure is wrapped in RefCell . Here's a little play:

 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()); } 

The compiler is angry:

 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 

Is there any other API I should use?

+5
source share
1 answer

You can manually call DerefMut and then save the resulting link:

 fn write(s: RefCell<S>) { let mut mut_s = s.borrow_mut(); let mut tmp = &mut *mut_s; let str = &tmp.data.string; tmp.writer.write(str.as_bytes()); } 

The problem is that borrow_mut does not return your structure directly - it returns RefMut . This is usually transparent, since this structure implements Deref and DerefMut , so any methods it DerefMut are passed to the base type. The pseudo-extended code looks something like this:

 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 does not track field-level borrowing between function calls (even for Deref::deref or DerefMut::deref_mut ). This leads to your error, since the deref_mut method deref_mut have to be called during Deref::deref borrowing from the previous Deref::deref .

An extended version with explicit borrowing is as follows, with a single call to 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()); } 

The compiler can then track that the two borrowings from this temporary value do not intersect.


Please note that this problem is not unique to RefCell ! Any type that implements DerefMut may run into the same problem. Here are some of the standard library:

+9
source

Source: https://habr.com/ru/post/1273061/


All Articles