Why can you borrow a mutable reference and still use both? - rust

#[derive(Debug)]
struct Rect {
width: u32,
height: u32,
}
fn main() {
let mut r = Rect { width: 30, height: 30 };
let b = &mut r;
let c: &Rect = b;
println!("{:?},{:?}", b, c);
}
In code, b is mutably borrowed and c is immutably borrowed, so this shouldn't compile, but that compiles and runs without any error.

this shouldn't compile
Why? Yes, b mutably borrows r. But c immutably borrows b, so now b is, well, immutably borrowed and you can't mutate it.
If you attempt to assign to any fields of b, then the compiler will immediately throw an error.
let mut r = Rect { width: 30, height: 30 };
let b = &mut r;
let c: &Rect = b;
// This assignment will fail, as yes, `b` is a
// mutable reference but it is immutably borrowed.
b.width = 40;
println!("{:?},{:?}", b, c);
The example is the same as if you remove b all together. You still wouldn't be able to mutate r, even though r is mutable.
let mut r = Rect { width: 30, height: 30 };
let c: &Rect = &r;
// This assignment will fail for the same reason,
// `r` is a mutable reference but it is immutably borrowed.
r.width = 40;
println!("{:?},{:?}", r, c);

Let's simplify and desugar your example:
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
println!("{:?},{:?}", b, c);
}
I think the source of confusion is that the prinln! macro looks like a regular function call but in reality isn't. If we replace the println! macro with a regular function:
fn func(format: &str, b: &mut i32, c: &i32) {}
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
func("{:?},{:?}", b, c);
}
Then we get the expected compiler error:
error[E0502]: cannot borrow `*b` as mutable because it is also borrowed as immutable
--> src/main.rs:7:5
|
6 | let c: &i32 = &*b;
| --- immutable borrow occurs here
7 | func("{:?},{:?}", b, c);
| ----^^^^^^^^^^^^^^^^^^^
| |
| mutable borrow occurs here
| immutable borrow later used by call
So the question now becomes why does println! work where func fails. Let's take a closer look at println! by expanding it:
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["", ",", "\n"],
&match (&b, &c) { // borrows b & c again here
(arg0, arg1) => [
::core::fmt::ArgumentV1::new(arg0, ::core::fmt::Debug::fmt),
::core::fmt::ArgumentV1::new(arg1, ::core::fmt::Debug::fmt),
],
},
));
};
}
The println! prepends & to its arguments, so if we revise func to do the same:
fn func(format: &str, b: &&mut i32, c: &&i32) {}
fn main() {
let mut a: i32 = 1;
let b: &mut i32 = &mut a;
let c: &i32 = &*b;
func("{:?},{:?}", &b, &c);
}
It now compiles.
So what have we learned here? If we mutably borrow some data, then immutably borrow from the mutable borrow, and then immutably borrow the mutable borrow and the immutable re-borrow of the mutable borrow, then there's no violation of Rust's ownership rules, since the immutable borrows are all borrowing from the same original mutable borrow which is not being mutated while the immutable borrows are alive.

Related

Decoupling ownership from vector

I'm creating factory methods for objects with shared references. The compiler cannot see that the objects from a Vec are not referenced outside the local scope, and that the newly created objects are not linked to the original objects.
How do I get around this issue, what am I missing?
#[derive(Debug)]
pub struct A {}
pub struct B<'b> {
a: &'b A,
}
impl<'b> B<'b> {
pub fn new(a: &'b A) -> B {
B { a: a }
}
pub fn combine(&self, _: &B) -> B {
B::new(self.a)
}
}
pub fn main() {
let a: A = A {};
let mut v1: Vec<B> = vec![];
v1.push(B::new(&a));
v1.push(B::new(&a));
let mut v2: Vec<B> = vec![];
{
let b1 = &v1[0]; // << Mutable borrow occurs here - why?
let b2 = &v1[1];
let c = b1.combine(&b2);
v2.push(c)
}
v1.clear(); // Error: Cannot borrow due to mutable borrow above
println!("{:?}", v2[0].a);
}
error[E0502]: cannot borrow `v1` as mutable because it is also borrowed as immutable
--> src/main.rs:32:5
|
27 | let b1 = &v1[0]; // << Mutable borrow occurs here - why?
| -- immutable borrow occurs here
...
32 | v1.clear(); // Error: Cannot borrow due to mutable borrow above
| ^^^^^^^^^^ mutable borrow occurs here
33 | println!("{:?}", v2[0].a);
| -- immutable borrow later used here
No, sorry, I still do not quite get it.
Here is an even simpler example, without vectors:
let a:A = A { };
let mut b1 = B::new(&a);
let mut b2 = B::new(&a);
let c = &b1.combine(&b2);
// ^^^ This creates a mutable reference to b1. How to avoid?
b1 = B::new(&a);
b2 = B::new(&a);
println!("{:?}",c.a);
For some reason, the method call on the object will make the compiler assume that I have a reference to the object, despite c having no reference to b1. How do I get around that?
How can I declare the combine()-method to be immutable?

Borrowing a borrowed mutable type

How can a function with a borrowed mutable reference call a second function with the same borrowed mutatble reference?
fn main() {
let mut a = vec![0, 1, 2, 3, 4];
first_function(&mut a);
println!("{:?}", a);
}
fn first_function(a: &mut Vec<i32>) {
println!("...first function");
a[0] = 5;
second_function(&mut a);
}
fn second_function(a: &mut Vec<i32>) {
println!("...second function");
a[2] = 6;
}
The compiler errors are normally very helpful, but I don't understand this one;
error[E0596]: cannot borrow `a` as mutable, as it is not declared as mutable
--> src/main.rs:12:21
|
9 | fn first_function(a: &mut Vec<i32>) {
| - help: consider changing this to be mutable: `mut a`
...
12 | second_function(&mut a);
| ^^^^^^ cannot borrow as mutable
... here's a link to the code in Rust Playground
By writing &mut a, you’re trying to take a mutable reference to a, not to what its value references – it would be a &mut &mut Vec<i32>. a’s value is already the mutable reference you want:
second_function(a);
updated playground

Mutable ref becomes immutable inside closure

I have this function to generate a random vector.
pub fn random_vec(r: &mut rng::Rng, n: u32) -> Vec<Flo> {
(0..n).map(|_| r.next_normal()).collect()
}
I use it to generate a vector of 3 random vectors like this.
let xs: Vec<Vec<Flo>> =
(0..3).map(|_| random_vec(&mut r, n)).collect();
This works fine. Now I try to extract this line into a function.
fn random_vecs(r: &mut rng::Rng, n: u32) -> Vec<Vec<Flo>> {
(0..3).map(|_| random_vec(&mut r, n)).collect()
}
This fails with message: "closure cannot assign to immutable argument `r`". Why does Rust want r to be immutable?
Technically, because the formal argument r of random_vecs is not mutable, and by the &mut r in the body you are trying to construct a mutable reference to it.
Here is a simplified example with the essentials of what you are doing:
fn modify0(r: &mut usize) {
*r += 1;
}
fn modify1(r: &mut usize) {
modify0(&mut r);
}
fn main() {
let mut a = 1;
modify1(&mut a);
println!("Hello, {:?}!", a);
}
The error message is
error[E0596]: cannot borrow immutable argument `r` as mutable
--> src/main.rs:6:18
|
6 | modify0(&mut r);
| ^ cannot borrow mutably
help: consider removing the `&mut`, as it is an immutable binding to a mutable reference
To fix it, you could make it mutable (don't, it's not a good idea, even though it works here):
fn modify1(mut r: &mut usize) {
modify0(&mut r);
}
Better is to follow the suggestion in the error message and remove the superfluous &mut:
fn modify1(r: &mut usize) {
modify0(r);
}

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.

In Rust, what exactly are mutable and immutable borrows?

I'm stuck with the Rust concepts of borrowing and mutable:
#[derive(Debug)]
struct Rectangle {
height: u32,
width: u32,
}
fn mut_area(rect_mut: &mut Rectangle) -> u32 {
rect_mut.width /= 2;
rect_mut.height * rect_mut.width
}
fn mut_string(s: &mut String) -> &str {
s.push_str("!");
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect);
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
let half = mut_string(&mut s);
println!("half of the modified string: {}", half);
println!("modified s: {}", s);
}
When I tried to compile it, the compiler told me:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> <anon>:32:32
|
30 | let half = mut_string(&mut s);
| - mutable borrow occurs here
31 | println!("half of the modified string: {}", half);
32 | println!("modified s: {}", s);
| ^ immutable borrow occurs here
33 | }
| - mutable borrow ends here
I know there's a rule about mutable reference:
you can only have one mutable reference to a particular piece of data in a particular scope.
But why can rect be borrowed but s cannot be? And how do I achieve what I want here - to print the modified string after the function call?
The reason why you can print a after calling a function with a mutable reference to rect is that it returns a u32 which is Copyable - there is no need to restrict further uses of rect because it is no longer borrowed after mut_area is called.
Your mut_string, on the other hand, returns a reference to its argument, so the mutable borrow remains in force as long as half is in scope. That's why you may not borrow s immutably for the purpose of println!().
In order to achieve what you are after I would mutate s outside of the mut_string function (a slightly different name would be a good idea now) so there is no mutable borrow in force - its argument can be borrowed immutably instead:
fn mut_string(s: &str) -> &str {
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect); // rect's mutable borrow expires after this assignment
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
s.push_str("!"); // s is mutated here
let half = mut_string(&s); // s is borrowed immutably
println!("half of the modified string: {}", half);
println!("modified s: {}", s); // another immutable borrow of s
}

Resources