This question already has answers here:
Can I reassign a mutable slice reference to a sub-slice of itself?
(2 answers)
Closed 2 years ago.
I want to uptade a slice through a mutable reference.
While this does work with immutable slices:
fn shrink(value: &mut &[u8]) {
*value = &value[0..2];
}
fn main() {
let a = [0; 4];
let mut a_slice: &[u8] = &a;
shrink(&mut a_slice);
println!("{:?}", a_slice);
}
It doesn't work with mutable ones:
fn shrink<'a: 'b, 'b>(value: &'a mut &'b mut [u8]) {
*value = &mut value[0..2];
}
fn main() {
let mut a = [0; 4];
let mut a_slice: &mut [u8] = &mut a;
shrink(&mut a_slice);
println!("{:?}", a_slice);
}
Error message:
error[E0502]: cannot borrow `a_slice` as immutable because it is also borrowed as mutable
--> src/main.rs:8:22
|
7 | shrink(&mut a_slice);
| ------------ mutable borrow occurs here
8 | println!("{:?}", a_slice);
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
I know that there is a way to update the slice by directly returning a subslice.
But is there a way to make rereferencing a mutable slice through mutable reference possible?
The problem is similar to this one, but I can't figure what makes it so different, that proposed solution doesn't work.
I don't know what the problem is with that code, but one option would be to return the updated slice directly:
fn shrink(value: &mut [u8]) -> &mut [u8] {
&mut value[0..2]
}
fn main() {
let mut a = [0; 4];
let mut a_slice = &mut a[..];
a_slice = shrink(a_slice);
println!("{:?}", a_slice);
}
Rather than updating via the mutable reference, updating in the caller makes it clear that the old value of a_slice won't be used any more.
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 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
This question already has answers here:
How to get mutable references to two array elements at the same time?
(8 answers)
Closed 4 years ago.
I'm trying to understand lifetimes and storing mutable slices inside a struct.
I came up with this example with a struct with a slice and a take function that will return n elements (if present) and store the rest in the structure itself. This code does not compile.
fn main() {
let mut v: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut blah = Blah { slice: &mut v[..] };
let b = blah.take(5);
println!("b: {:?}", b);
}
#[derive(Debug)]
struct Blah<'a> {
slice: &'a mut [u8],
}
impl<'a> Blah<'a> {
pub fn take(&'a mut self, n: usize) -> Option<Self> {
if self.slice.len() > n {
let blah = Blah {
slice: &mut self.slice[..n],
};
self.slice = &mut self.slice[n..];
Some(blah)
} else {
None
}
}
}
Compiler error:
error[E0499]: cannot borrow `*self.slice` as mutable more than once at a time
--> src/main.rs:21:31
|
15 | impl<'a> Blah<'a> {
| -- lifetime `'a` defined here
...
19 | slice: &mut self.slice[..n],
| ---------- first mutable borrow occurs here
20 | };
21 | self.slice = &mut self.slice[n..];
| ^^^^^^^^^^ second mutable borrow occurs here
22 | Some(blah)
| ---------- returning this value requires that `*self.slice` is borrowed for `'a`
I have a large in-memory buffer that I don't want to copy. Instead, I want to keep referring to the same memory by carrying around "fat pointers" (something like offset + length).
The Rust compiler isn't able to detect that the two borrows of sub-slices are non-overlapping. When you borrow &mut self.slice[..n], the whole of self.slice is considered to be borrowed, so you can't then borrow the remaining elements.
There is a method split_at_mut, designed to solve this problem by producing two disjoint mutable borrows from a slice. Your code can be updated to use it like this:
impl<'a> Blah<'a> {
pub fn take(&'a mut self, n: usize) -> Option<Self> {
if self.slice.len() > n {
let (left, right) = self.slice.split_at_mut(n);
let blah = Blah {
slice: left
};
self.slice = right;
Some(blah)
} else {
None
}
}
}
I am implementing an in-place recursive parser in rust and I am getting some borrow errors. The code snippet reproduces the problem although it is not very useful
use std::vec::Vec;
struct MyBorrows<'a> {
val : &'a mut i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a mut i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let mut my_val = 23;
let mut my_vec : Vec<Box<MyBorrows>> = Vec::new();
my_vec.push(Box::new(MyBorrows::new(&mut my_val)));
for i in [1..4].iter() {
let mut last : &mut Box<MyBorrows> = my_vec.last_mut().unwrap();
let mut new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
This gives me the following error:
error[E0499]: cannot borrow `my_vec` as mutable more than once at a time
--> test.rs:20:9
|
18 | let mut last : &mut Box = my_vec.last_mut().unwrap();
| ------ first mutable borrow occurs here
19 | let mut new_borrow = Box::new(MyBorrows::new(last.val));
20 | my_vec.push(new_borrow);
| ^^^^^^ second mutable borrow occurs here
21 | }
22 | }
| - first borrow ends here
error: aborting due to 3 previous errors
In my real case, the vector is used as a stack to reference deeper and deeper components of the struct I am parsing into. This is common pattern I use for general purpose parsing in C++ which I am trying to replicate in Rust but I am having problems. Any help will be appreciated.
What you are trying to do is unsound. It looks like you are attempting to create multiple MyBorrows which all mutably borrow the same value, and have them all alive at once (in the vector). Such setups are exactly what Rust is designed to prevent, as that's how data races occur.
What you might instead want to do is immutably borrow the value a bunch, which is legal. So after cleaning up the unnecessary mutable borrows, I've reduced the problem to:
struct MyBorrows<'a> {
val : &'a i32
}
impl <'a> MyBorrows<'a> {
fn new(v : &'a i32) -> MyBorrows<'a> {
MyBorrows { val : v }
}
}
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let last = my_vec.last().unwrap();
let new_borrow = Box::new(MyBorrows::new(last.val));
my_vec.push(new_borrow);
}
}
You get a slightly different error now:
error[E0502]: cannot borrow `my_vec` as mutable because it is also borrowed as immutable
--> test.rs:18:9
|
16 | let last = my_vec.last().unwrap();
| ------ immutable borrow occurs here
17 | let new_borrow = Box::new(MyBorrows::new(last.val));
18 | my_vec.push(new_borrow);
| ^^^^^^ mutable borrow occurs here
19 | }
| - immutable borrow ends here
error: aborting due to previous error
This one is trickier, and you have to realize what is going on when you call my_vec.last() -- it's returning a reference to existing memory in the Vec, precluding anything else from touching the Vec. Currently in Rust, this reference lives until the end of the current block. To get around this, encase the mutable borrow in its own block scope:
fn main() {
let my_val = 23;
let mut my_vec = vec![];
my_vec.push(Box::new(MyBorrows::new(&my_val)));
for _ in 1..4 {
let new_borrow;
{
let last = my_vec.last().unwrap();
new_borrow = Box::new(MyBorrows::new(last.val));
}
my_vec.push(new_borrow);
}
}
Now the mutable borrow ends before the push occurs, and the lifetimes work. Hopefully in the future, we will get non-lexical lifetimes added to the language, so the compiler can figure out that my first example is actually safe.
I'm trying to navigate a recursive data structure iteratively in order to insert elements at a certain position. To my limited understanding, this means taking a mutable reference to the root of the structure and successively replacing it by a reference to its follower:
type Link = Option<Box<Node>>;
struct Node {
next: Link
}
struct Recursive {
root: Link
}
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while let Some(ref mut node) = *anchor {
anchor = &mut node.next;
}
anchor
}
}
(Rust playground link)
However, this fails:
error[E0499]: cannot borrow `anchor.0` as mutable more than once at a time
--> src/main.rs:14:24
|
14 | while let Some(ref mut node) = *anchor {
| ^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first mutable borrow occurs here
...
18 | }
| - first borrow ends here
error[E0506]: cannot assign to `anchor` because it is borrowed
--> src/main.rs:15:13
|
14 | while let Some(ref mut node) = *anchor {
| ------------ borrow of `anchor` occurs here
15 | anchor = &mut node.next;
| ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `anchor` occurs here
error[E0499]: cannot borrow `*anchor` as mutable more than once at a time
--> src/main.rs:17:9
|
14 | while let Some(ref mut node) = *anchor {
| ------------ first mutable borrow occurs here
...
17 | anchor
| ^^^^^^ second mutable borrow occurs here
18 | }
| - first borrow ends here
This makes sense as both anchor and node refer to the same structure, but I actually don't care about anchor any more after destructuring it.
How could back() be implemented correctly using safe Rust?
It is possible... but I wish I had a more elegant solution.
The trick is NOT to borrow from anchor, and therefore to juggle between two accumulators:
one holding the reference to the current node
the other being assigned the reference to the next node
This leads me to:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
let tmp = anchor;
if let Some(ref mut node) = *tmp {
anchor = &mut node.next;
} else {
anchor = tmp;
break;
}
}
anchor
}
}
Not exactly pretty, but this is something the borrow checker can get behind so ¯\_(ツ)_/¯.
#ker has improved on this by creating an unnamed temporary:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
match {anchor} {
&mut Some(ref mut node) => anchor = &mut node.next,
other => return other,
}
}
}
}
The trick here is that using {anchor} moves the content of anchor into an unnamed temporary on which the match executes. Therefore, in the match block we are not borrowing from anchor but from the temporary, leaving us free to modify anchor. See the related blog post Stuff the Identity Function Does (in Rust).
The original code works as-is once non-lexical lifetimes are enabled:
type Link = Option<Box<Node>>;
struct Node {
next: Link,
}
struct Recursive {
root: Link,
}
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while let Some(node) = anchor {
anchor = &mut node.next;
}
anchor
}
}
Non-lexical lifetimes increases the precision of the compiler's borrow checker, allowing it to see that the mutable borrow of anchor is no longer used. We can also simplify the keywords in the if let due to recent language changes.
You can use recursion to satisfy the borrow checker. This has the disadvantage of creating a stack frame for every item in your list. If your list is long, this will definitely run into a stack overflow. LLVM will optimize the Node::back method into a loop (see the LLVM IR generated on the playground)
impl Node {
fn back(&mut self) -> &mut Link {
match self.next {
Some(ref mut node) => node.back(),
None => &mut self.next,
}
}
}
impl Recursive {
fn back(&mut self) -> Option<&mut Link> {
self.root.as_mut().map(|node| node.back())
}
}
It works:
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while anchor.is_some(){
anchor = &mut {anchor}.as_mut().unwrap().next;
}
anchor
}