Borrowing mutable twice while using the same variable - rust

Suppose that I'm going through a vector (not necessarily linearly, so I can't just use map) and I need to change an element when it satisfies some condition. I would think to use some variable to keep track of where I am, for example, something like a current variable
let mut v = vec![1, 2, 3, 4];
let mut current = &mut v[0];
and then check current to for some condition to see if it needs to be changed. However, when I do
current = &mut v[1];
It gives me the cannot borrow v as mutable more than once at a time.
I feel like this should be allowed, since I've only used one variable, and I can't access the old borrow any more.
Is there some way I can let rust know that I'm giving the first borrow back, so I'm not borrowing twice? Or have I been thinking about this wrong, and there is a different rust idiom I should use? I've solved this problem by using the indeces for the vector instead of a mutable reference, but I think this problem of "traversing using a current and then changing it" goes beyond just vectors. What if the data structure I had didn't have indeces?

The mutable reference exists until the variable goes out of scope, so you can have several mutable borrows in sequence by putting blocks around each one:
fn do_stuff(n: &mut usize) {
*n += 1;
}
fn main() {
let mut v = vec![1, 2, 3, 4];
{
let current = &mut v[1];
do_stuff(current);
}
{
let current = &mut v[0];
do_stuff(current);
}
println!("{:?}", v);
}
This is unnecessary with non-lexical lifetimes, which are currently only available on the nightly version:
#![feature(nll)]
fn do_stuff(n: &mut usize) {
*n += 1;
}
fn main() {
let mut v = vec![1, 2, 3, 4];
let mut current = &mut v[1];
do_stuff(current);
current = &mut v[0];
do_stuff(current);
println!("{:?}", v);
}

If you want to access more than one, you have to create a scope.
fn main() {
let mut vec = vec![2, 3, 5];
{
let mut current1 = vec.get_mut(1);
println!("{:?}", current1);
}
{
let mut current2 = vec.get_mut(2);
println!("{:?}", current2);
}
for i in 0..3 {
let mut current = vec.get_mut(i);
println!("{:?}", current);
}
}

Related

"Cannot borrow `*arr` as immutable because it is also borrowed as mutable" in a function call

Please someone explain the code below and how can it be unsafe and why is borrowchecker complaining here? I am very new to rust and I come from a little bit of c/c++ background.
fn test(a: &mut [i32], place: usize) -> i32 {
a[place] /= 2;
return a[place];
}
fn main() {
let mut values = vec![1, 2, 3, 4];
let b = test(&mut values, values.len() / 2); // compiler gives error on values.len()
}
Why does it work with first assigning a variable with values.len()/2 and passing that to the function?
The problem occurs because you are trying to do two different things to values in two different argument positions and the current Rust implementation is not smart enough to determine that this use case is not problematic.
You can fix this by doing this instead:
fn test(a: &mut [i32], place: usize) -> i32 {
a[place] /= 2;
return a[place];
}
fn main() {
let mut values = vec![1, 2, 3, 4];
let l = values.len() / 2;
let b = test(&mut values, l);
}

Allocating struct objects on heap inside loop in rust

I need to allocate structs with a drop trait inside a for loop and have a mutable reference for downstream processing. I have created this minimal example code that I can't compile with rust version 1.59. I have tried using the internal mutability with Rc and RefCell as well.
use std::cell::RefCell;
use std::rc::Rc;
// MyVec with Drop Trait
struct MyVec {
vec: Vec<i32>,
}
impl Drop for MyVec {
fn drop(&mut self) {
println!("Dropping MyVec with data `{:?}`!", self.vec);
}
}
impl MyVec {
// Get a mutable slice
fn mut_slice(&mut self) -> &mut [i32]{
return &mut self.vec[..]
}
}
pub fn test() {
// Needed for downstream purposes
let mut all_slices = Vec::new();
// Storing reference counter Rc and RefCell combo
// Hoping to prevent allocated MyVec objects from dropping and have one mutable reference
let mut all_refs = Vec::new();
for _i in 0..1 {
let my_vec = Rc::new(RefCell::new(MyVec {
vec: vec![1, 2, 3]
}));
// Make a clone of my_vec to prevent it from dropping
all_refs.push(Rc::clone(&my_vec));
let mut my_vec_mut = my_vec.borrow_mut();
let x = my_vec_mut.mut_slice();
all_slices.push(x);
}
println!("{:?}", all_slices);
}
The same code works when I unroll the loop and write the following code:
pub fn test() {
// Needed for downstream purposes
let mut all_slices = Vec::new();
// Storing reference counter Rc and RefCell combo
// Hoping to prevent allocated MyVec objects from dropping and have one mutable reference
let mut all_refs = Vec::new();
let my_vec = Rc::new(RefCell::new(MyVec {
vec: vec![1, 2, 3]
}));
// Make a clone of my_vec to prevent it from dropping
all_refs.push(Rc::clone(&my_vec));
let mut my_vec_mut = my_vec.borrow_mut();
let x = my_vec_mut.mut_slice();
all_slices.push(x);
println!("{:?}", all_slices);
}
Update: Thanks to Masklinn's comments, I fixed the code. I needed to create objects in the loop and required a mutable reference to its internal data field outside the scope of the loop. The rust compiler showed an error that the references outlive the object itself. Finally, I used a separate loop to allocate the objects and a second loop with iter_mut to create mutable references. Here is the final code:
pub fn test() {
// Needed for downstream purposes
let mut all_slices = Vec::new();
// Hoping to prevent allocated MyVec objects from dropping and have one mutable reference
let mut all_vecs = Vec::new();
for _i in 0..1 {
all_vecs.push(MyVec {
vec: vec![1, 2, 3]
});
}
for my_vec in all_vecs.iter_mut() {
all_slices.push(my_vec.mut_slice());
}
println!("{:?}", all_slices);
}

What is a reborrow and how does it influence the code the compiler generates?

Part of the assert_eq macro code is:
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
// The reborrows below are intentional. Without them, the stack slot for the
// borrow is initialized even before the values are compared, leading to a
// noticeable slow down.
$crate::panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`: {}"#, &*left_val, &*right_val,
$crate::format_args!($($arg)+))
}
}
}
});
The comment says that the reborrow is intentional and that it would somehow influence how stack is used.
What is a reborrow and how does it influence the code the compiler generates?
I am not sure how it affects compilation but a reborrow is when you dereference something and then borrow it straight after.
For example:
fn main() {
let mut vec: Vec<u8> = vec![1, 2, 3];
let mut_ref: &mut Vec<u8> = &mut vec;
let reborrow: &Vec<u8> = &*mut_ref;
}
It can be used to:
get an immutable reference from a mutable reference (code above)
get a reference with a shorter lifetime
get a reference to something in a smart pointer
get a reference from a pointer
and probably other things too.. (I am fairly new to Rust 😃)
Example use for shortening lifetime (very contrived but this is oversimplified):
fn main() {
let mut outer_vec = vec![1, 2, 3];
let outer_ref = &mut outer_vec;
{
// shorten lifetime of outer_ref
// not doing this causes an error
let mut outer_ref = &mut *outer_ref; // mutable reborrow
let mut inner_vec = vec![1, 2, 3];
let inner_ref = &mut inner_vec;
// imagine a real condition
if true {
outer_ref = inner_ref;
}
// use outer_ref which could point to the outer_vec or inner_vec
println!("{:?}", outer_ref);
}
println!("{:?}", outer_ref);
}
Getting a reference to something behind a smart pointer (Box in this case):
fn main() {
let vec = vec![1, 2, 3];
let boxed = Box::new(vec);
let reborrow: &Vec<u8> = &*boxed;
println!("{:?}", reborrow);
}
Reference from pointer:
fn main() {
let num: u8 = 10;
let pointer: *const u8 = &num as *const u8;
unsafe {
let ref_from_ptr: &u8 = &*pointer;
}
}
Not sure if all of these are strictly considered a "reborrow" by the way.

How can I borrow from a HashMap to read and write at the same time?

I have a function f that accepts two references, one mut and one not mut. I have values for f inside a HashMap:
use std::collections::HashMap;
fn f(a: &i32, b: &mut i32) {}
fn main() {
let mut map = HashMap::new();
map.insert("1", 1);
map.insert("2", 2);
{
let a: &i32 = map.get("1").unwrap();
println!("a: {}", a);
let b: &mut i32 = map.get_mut("2").unwrap();
println!("b: {}", b);
*b = 5;
}
println!("Results: {:?}", map)
}
This doesn't work because HashMap::get and HashMap::get_mut attempt to mutably borrow and immutably borrow at the same time:
error[E0502]: cannot borrow `map` as mutable because it is also borrowed as immutable
--> src/main.rs:15:27
|
12 | let a: &i32 = map.get("1").unwrap();
| --- immutable borrow occurs here
...
15 | let b: &mut i32 = map.get_mut("2").unwrap();
| ^^^ mutable borrow occurs here
...
18 | }
| - immutable borrow ends here
In my real code I'm using a large, complex structure instead of a i32 so it is not a good idea to clone it.
In fact, I'm borrowing two different things mutably/immutably, like:
struct HashMap {
a: i32,
b: i32,
}
let mut map = HashMap { a: 1, b: 2 };
let a = &map.a;
let b = &mut map.b;
Is there any way to explain to the compiler that this is actually safe code?
I see how it possible to solve in the concrete case with iter_mut:
{
let mut a: &i32 = unsafe { mem::uninitialized() };
let mut b: &mut i32 = unsafe { mem::uninitialized() };
for (k, mut v) in &mut map {
match *k {
"1" => {
a = v;
}
"2" => {
b = v;
}
_ => {}
}
}
f(a, b);
}
But this is slow in comparison with HashMap::get/get_mut
TL;DR: You will need to change the type of HashMap
When using a method, the compiler does not inspect the interior of a method, or perform any runtime simulation: it only bases its ownership/borrow-checking analysis on the signature of the method.
In your case, this means that:
using get will borrow the entire HashMap for as long as the reference lives,
using get_mut will mutably borrow the entire HashMap for as long as the reference lives.
And therefore, it is not possible with a HashMap<K, V> to obtain both a &V and &mut V at the same time.
The work-around, therefore, is to avoid the need for a &mut V entirely.
This can be accomplished by using Cell or RefCell:
Turn your HashMap into HashMap<K, RefCell<V>>,
Use get in both cases,
Use borrow() to get a reference and borrow_mut() to get a mutable reference.
use std::{cell::RefCell, collections::HashMap};
fn main() {
let mut map = HashMap::new();
map.insert("1", RefCell::new(1));
map.insert("2", RefCell::new(2));
{
let a = map.get("1").unwrap();
println!("a: {}", a.borrow());
let b = map.get("2").unwrap();
println!("b: {}", b.borrow());
*b.borrow_mut() = 5;
}
println!("Results: {:?}", map);
}
This will add a runtime check each time you call borrow() or borrow_mut(), and will panic if you ever attempt to use them incorrectly (if the two keys are equal, unlike your expectations).
As for using fields: this works because the compiler can reason about borrowing status on a per-field basis.
Something appears to have changed since the question was asked. In Rust 1.38.0 (possibly earlier), the following compiles and works:
use std::collections::HashMap;
fn f(a: &i32, b: &mut i32) {}
fn main() {
let mut map = HashMap::new();
map.insert("1", 1);
map.insert("2", 2);
let a: &i32 = map.get("1").unwrap();
println!("a: {}", a);
let b: &mut i32 = map.get_mut("2").unwrap();
println!("b: {}", b);
*b = 5;
println!("Results: {:?}", map)
}
playground
There is no need for RefCell, nor is there even a need for the inner scope.

How can I swap items in a vector, slice, or array in Rust?

My code looks like this:
fn swap<T>(mut collection: Vec<T>, a: usize, b: usize) {
let temp = collection[a];
collection[a] = collection[b];
collection[b] = temp;
}
Rust is pretty sure I'm not allowed to "move out of dereference" or "move out of indexed content", whatever that is. How do I convince Rust that this is possible?
There is a swap method defined for &mut [T]. Since a Vec<T> can be mutably dereferenced as a &mut [T], this method can be called directly:
fn main() {
let mut numbers = vec![1, 2, 3];
println!("before = {:?}", numbers);
numbers.swap(0, 2);
println!("after = {:?}", numbers);
}
To implement this yourself, you have to write some unsafe code. Vec::swap is implemented like this:
fn swap(&mut self, a: usize, b: usize) {
unsafe {
// Can't take two mutable loans from one vector, so instead just cast
// them to their raw pointers to do the swap
let pa: *mut T = &mut self[a];
let pb: *mut T = &mut self[b];
ptr::swap(pa, pb);
}
}
It takes two raw pointers from the vector and uses ptr::swap to swap them safely.
There is also a mem::swap(&mut T, &mut T) when you need to swap two distinct variables. That cannot be used here because Rust won't allow taking two mutable borrows from the same vector.
As mentioned by #gsingh2011, the accepted answer is no longer good approach. With current Rust this code works fine:
fn main() {
let mut numbers = vec![1, 2, 3];
println!("before = {:?}", numbers);
numbers.swap(0, 2);
println!("after = {:?}", numbers);
}
try it here

Resources