I have a struct which contains both data and a writer which will eventually be used to write the data. The struct is wrapped in a RefCell. Here's a small reproduction:
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 a different API I should use?
You can manually invoke DerefMut and then save the resulting reference:
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());
}
Or in one line:
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());
}
The problem is that borrow_mut doesn't return your struct directly — it returns a RefMut. Normally, this is transparent as this struct implements Deref and DerefMut, so any methods called on it are passed to the underlying type. The pseudo-expanded 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 doesn't track field-level borrows across function calls (even for Deref::deref or DerefMut::deref_mut). This causes your error, as the deref_mut method would need to be called during the outstanding borrow from the previous Deref::deref.
The expanded version with the explicit borrow looks like this, 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 borrows from that temporary value are disjoint.
Note that this problem isn't unique to RefCell! Any type that implements DerefMut can experience the same problem. Here's some from the standard library:
Box
MutexGuard (from Mutex)
PeekMut (from BinaryHeap)
RwLockWriteGuard (from RwLock)
String
Vec
Pin
Related
I have a struct which contains both data and a writer which will eventually be used to write the data. The struct is wrapped in a RefCell. Here's a small reproduction:
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 a different API I should use?
You can manually invoke DerefMut and then save the resulting reference:
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());
}
Or in one line:
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());
}
The problem is that borrow_mut doesn't return your struct directly — it returns a RefMut. Normally, this is transparent as this struct implements Deref and DerefMut, so any methods called on it are passed to the underlying type. The pseudo-expanded 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 doesn't track field-level borrows across function calls (even for Deref::deref or DerefMut::deref_mut). This causes your error, as the deref_mut method would need to be called during the outstanding borrow from the previous Deref::deref.
The expanded version with the explicit borrow looks like this, 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 borrows from that temporary value are disjoint.
Note that this problem isn't unique to RefCell! Any type that implements DerefMut can experience the same problem. Here's some from the standard library:
Box
MutexGuard (from Mutex)
PeekMut (from BinaryHeap)
RwLockWriteGuard (from RwLock)
String
Vec
Pin
I have a code looks like this:
use std::collections::HashMap;
fn main() {
let x = get_hash_map();
println!("{:?}", x);
}
fn get_hash_map() -> Option<&'static Vec<i32>> {
let mut hm = HashMap::new();
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
return hm.get("1");
}
But I got this error:
error[E0515]: cannot return value referencing local variable `hm`
--> src/main.rs:13:12
|
13 | return hm.get("1");
| --^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `hm` is borrowed here
Here is the rust playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7605176aee2dd3ff77a0cfd04a89db55
Can anyone suggest the alternatives to fix this problem minimally? Thanks!
fn get_hash_map() -> Option<&'static Vec<i32>> {
let mut hm = HashMap::new();
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
return hm.get("1");
}
This is invalid, because you have declared you are going to return an Option<&'static Vec<i32>>, but you are returning an Option<&'a Vec<i32>> where 'a is the current function lifetime. The HashMap will stop existing as soon as the function returns, freeing the vector, and the reference will then become dangling. This is the exact kind of situation the borrow checker is designed to avoid.
Just return the vector by value:
fn get_hash_map() -> Option<Vec<i32>> {
let mut hm = HashMap::new();
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
return hm.remove("1");
}
remove moves the value out of the map, returning it as an Option<V>.
If you then need an Option<&Vec<i32>>, you can just use as_ref() on your Option<Vec<i32>> to get one. Always remember it will become invalid as soon as its value goes out of scope.
The HashMap hm is local to the scope of the get_hash_map() function and is dropped as soon as get_hash_map() returns. The value returned by hm.get("1") contains a reference to this HashMap, thus its lifetime is also tied to the scope of get_hash_map() which unfortunately is shorter than the ascribed 'static lifetime.
If you remove the 'static lifetime and replaced it by some 'a annotation on the function, you would get a similar error, since again there is no (sound) way to return borrowed data from a function that creates the owner of that data.
You can however create the map in the surrounding scope and pass it via a mutable reference to get_hash_map
use std::collections::HashMap;
fn main() {
let mut hm = HashMap::new();
let x = get_hash_map(&mut hm);
println!("{:?}", x);
}
// note that both `hm` and the reference in the return type have the same 'a lifetime.
fn get_hash_map<'a>(hm: &'a mut HashMap<String, Vec<i32>>) -> Option<&'a Vec<i32>> {
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
hm.get("1");
}
I have a struct which contains both data and a writer which will eventually be used to write the data. The struct is wrapped in a RefCell. Here's a small reproduction:
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 a different API I should use?
You can manually invoke DerefMut and then save the resulting reference:
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());
}
Or in one line:
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());
}
The problem is that borrow_mut doesn't return your struct directly — it returns a RefMut. Normally, this is transparent as this struct implements Deref and DerefMut, so any methods called on it are passed to the underlying type. The pseudo-expanded 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 doesn't track field-level borrows across function calls (even for Deref::deref or DerefMut::deref_mut). This causes your error, as the deref_mut method would need to be called during the outstanding borrow from the previous Deref::deref.
The expanded version with the explicit borrow looks like this, 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 borrows from that temporary value are disjoint.
Note that this problem isn't unique to RefCell! Any type that implements DerefMut can experience the same problem. Here's some from the standard library:
Box
MutexGuard (from Mutex)
PeekMut (from BinaryHeap)
RwLockWriteGuard (from RwLock)
String
Vec
Pin
I have a struct which contains both data and a writer which will eventually be used to write the data. The struct is wrapped in a RefCell. Here's a small reproduction:
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 a different API I should use?
You can manually invoke DerefMut and then save the resulting reference:
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());
}
Or in one line:
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());
}
The problem is that borrow_mut doesn't return your struct directly — it returns a RefMut. Normally, this is transparent as this struct implements Deref and DerefMut, so any methods called on it are passed to the underlying type. The pseudo-expanded 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 doesn't track field-level borrows across function calls (even for Deref::deref or DerefMut::deref_mut). This causes your error, as the deref_mut method would need to be called during the outstanding borrow from the previous Deref::deref.
The expanded version with the explicit borrow looks like this, 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 borrows from that temporary value are disjoint.
Note that this problem isn't unique to RefCell! Any type that implements DerefMut can experience the same problem. Here's some from the standard library:
Box
MutexGuard (from Mutex)
PeekMut (from BinaryHeap)
RwLockWriteGuard (from RwLock)
String
Vec
Pin
In the following example, t1 compiles but t2 does not.
Is there anything special about &mut &stream? I don't think Deref kicks in.
use std::net::TcpStream;
fn t1() {
let stream = TcpStream::connect("127.0.0.1").unwrap();
let a = &mut &stream;
}
fn t2(stream: &TcpStream) {
let a = &mut stream;
}
Playground
9 | fn t2(stream: &TcpStream) {
| ------ use `mut stream` here to make mutable
10 | let a = &mut stream;
| ^^^^^^ cannot borrow mutably
&mut &foo
This does two things - it creates a temporary value of type &Foo, then creates another temporary of type &mut &Foo.
let a_ref_to_foo = &foo;
&mut a_ref_to_foo
This also creates a temporary of type &mut &Foo, but to something that is observable via the variable binding a_ref_to_foo, not another temporary.
The problem is the same as this example:
// Works
String::new().clear();
// Doesn't work
let s = String::new();
s.clear();
When you have a temporary value, you have ownership over it which includes treating it as mutable. Once it's been assigned to a binding, the binding has ownership and you must indicate that it's allowed to be mutated or not.