In Rust, what exactly are mutable and immutable borrows? - reference

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
}

Related

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

#[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.

Why does this not count as an immutable borrow?

I am reading the official Rust Book and looking at listing 4-8 in Section 4.3.
The code looks like this:
fn first_word(s: &String) -> usize {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return i;
}
}
s.len()
}
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear();
}
This line:
let word = first_word(&s);
seems to borrow an immutable reference to s. (This is where I guess I'm wrong; I just don't know why.)
In the next line, we mutate s by calling the clear() method.
I was expecting the compiler to throw:
cannot borrow `s` as mutable because it is also borrowed as immutable
Why does this compile?
The string s is immutably borrowed for the duration of the call to first_word. As soon as the control is returned to main after first_word, the string is not considered borrowed anymore and can be mutated as you have observed.
If first_word were to return a &String which you extended the lifetime of by assigning it to a variable, then you would see the error you expected. E.g.
fn first_word(s: &String) -> &String {
&s
}
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear();
}
cannot borrow s as mutable because it is also borrowed as immutable
https://rust.godbolt.org/z/cMVdVf
In that case, adding an extra scope would fix that:
fn main() {
let mut s = String::from("hello world");
{
let word = first_word(&s);
}
s.clear();
}

Code works without borrowing but I can't make it work with borrowing

I have some code and it works but AFAIK borrowing is made specifically to avoid passing same object in and out of method manually like I did in split_text method.
fn main() {
println!("Hello, world!");
let mut test = String::from("12345");
let mut obj1 = Object {
text: test.as_mut_str(),
next: None,
};
for i in 0..5 {
obj1 = obj1.split_text(4 - i);
if let Some(obj) = obj1.next.as_ref() {
println!("{}", obj.text);
}
}
}
struct Object<'a> {
text: &'a mut str,
next: Option<Box<Object<'a>>>,
}
impl<'a> Object<'a> {
fn split_text(mut self, count: usize) -> Self {
let tmp = self.text;
let (part1, part2) = tmp.split_at_mut(count);
self.text = part1;
let obj2 = Object {
text: part2,
next: None,
};
self.next = Some(Box::new(obj2));
self
}
}
(Playground)
But I can't figure out how to pass borrow checker
impl<'a> Object<'a> {
fn split_text(&'a mut self, count: usize) {
let tmp = &mut self.text;
let (part1, part2) = tmp.split_at_mut(count);
self.text = part1;
let obj2 = Object {
text: part2,
next: None,
};
self.next = Some(Box::new(obj2));
}
}
result in the error
error[E0499]: cannot borrow `obj1` as mutable more than once at a time
--> src/main.rs:11:9
|
11 | obj1.split_text(4 - i);
| ^^^^ mutable borrow starts here in previous iteration of loop
error[E0502]: cannot borrow `obj1.next` as immutable because it is also borrowed as mutable
--> src/main.rs:12:28
|
11 | obj1.split_text(4 - i);
| ---- mutable borrow occurs here
12 | if let Some(obj) = obj1.next.as_ref() {
| ^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
error[E0506]: cannot assign to `self.text` because it is borrowed
--> src/main.rs:27:9
|
23 | impl <'a> Object<'a> {
| -- lifetime `'a` defined here
24 | fn split_text(&'a mut self, count:usize) {
25 | let tmp = &mut self.text;
| -------------- borrow of `self.text` occurs here
26 | let (part1, part2) = tmp.split_at_mut(count);
| ----------------------- argument requires that `self.text` is borrowed for `'a`
27 | self.text = part1;
| ^^^^^^^^^^^^^^^^^ assignment to borrowed `self.text` occurs here
(Playground)
Is there a way to make this code to work?
The issue is that you are borrowing the object obj1 mutable in function split_text for 'a lifetime which is up to the end of the main function.
fn main() {
println!("Hello, world!");
let mut test = String::from("12345");
let mut obj1 = Object { // 'a start
text: test.as_mut_str(),
next: None,
};
for i in 0..5 {
obj1 = obj1.split_text(4 - i); // borrow for 'a lifetime,
// Won't work in next iteration
if let Some(obj) = obj1.next.as_ref() { // Won't work
println!("{}", obj.text);
}
}
} // 'a end
You want to borrow it mutably only for split_text function i.e. for a different (smaller) lifetime - which you can either elide or specify a different one - say 'b.
struct Object<'a> {
text: &'a str, // no need of mutable slice here
next: Option<Box<Object<'a>>>,
}
impl<'a> Object<'a> {
fn split_text(&mut self, count: usize) { // No lifetime required here
let (part1, part2) = self.text.split_at(count); // no need of temp var and mutable split here
self.text = part1;
let obj2 = Object {
text: part2,
next: None,
};
self.next = Some(Box::new(obj2));
}
}
Explicit different lifetime version (just for completeness):
impl<'a> Object<'a> {
fn split_text<'b>(&'b mut self, count: usize) {
let tmp = &mut self.text;
let (part1, part2) = tmp.split_at(count);
self.text = part1;
let obj2 = Object {
text: part2,
next: None,
};
self.next = Some(Box::new(obj2));
}
}
Also, make something mutable only when required. I changed the mutable slice and split to normal.

Borrow checker doesn't allow returning a mutable reference from tree traversal function

I need to find the node with maximal value in tree, assuming that subnode's values are always larger than value of owning node, and then modify it:
#[derive(Debug)]
struct Node {
val: usize,
nodes: Vec<Node>,
}
fn find_max(node: &mut Node, val: usize) -> Option<&mut Node> {
if node.val < val {
return None;
}
let mut max_val = node.val;
let mut max: Option<&mut Node> = Some(node);
for n in &mut node.nodes {
if let Some(m) = find_max(n, max_val) {
max_val = m.val;
max = Some(m);
}
}
max
}
fn main() {
let mut root = Node {
val: 1,
nodes: vec![
Node {
val: 2,
nodes: vec![],
},
Node {
val: 3,
nodes: vec![
Node {
val: 4,
nodes: vec![],
},
],
},
],
};
println!("{:?}", find_max(&mut root, 0));
}
The borrow checker returns this error:
error[E0499]: cannot borrow `node.nodes` as mutable more than once at a time
--> src/main.rs:13:19
|
12 | let mut max: Option<&mut Node> = Some(node);
| ---- first mutable borrow occurs here
13 | for n in &mut node.nodes {
| ^^^^^^^^^^ second mutable borrow occurs here
...
20 | }
| - first borrow ends here
If I remove mut from find_max, it works, but I don't see how can I return a mutable reference from find_max.
The important thing is that find_max itself doesn't modify anything. It just searches for an appropriate node.
It is not required to use unsafe:
fn find_max(node: &mut Node, val: usize) -> Option<&mut Node> {
if node.val < val {
return None;
}
if node.nodes.is_empty() {
return Some(node);
}
let mut max_val = node.val;
let mut max = None;
for n in &mut node.nodes {
if let Some(m) = find_max(n, max_val) {
max_val = m.val;
max = Some(m);
}
}
max
}
It seems to be one of rare cases when unsafe is justified.
The usual approach in such cases is to replace mutable reference with immutable reference and use interior mutability. But in this case we need to borrow() RefCells recursively and somehow keep them alive even after function returns.
Taking into account that the problem is caused not by inherent unsafety of the operation, but by a limitation of Rust's borrow checker, it makes sense to use unsafe. Keep in mind that while I reasonably sure that the following code is safe, it's better to wait for comments or another solution.
fn find_max(node: &mut Node, val: usize) -> Option<&mut Node> {
if node.val < val {
return None;
}
let mut max = None;
let mut max_val = node.val;
// keep reference around as a pointer
let node_ptr = node as *mut Node;
// `{ node }` moves the reference instead of reborrowing it
// so we can recreate it later with no risk of undefined behavior
for n in &mut { node }.nodes {
if let Some(m) = find_max(n, max_val) {
max_val = m.val;
max = Some(m);
}
}
max.or_else(
// the closure is executed only when `max == None`
// and `node` was moved out earlier in `{node}`
// therefore there's no active mutable references reachable thru recreated reference
// function signature ensures that lifetime of the returned reference is ok
// thus we can safely recreate the same mutable reference we received in `node`
|| unsafe { node_ptr.as_mut() }
)
}
U can use * instead &mut to deref .but [Node] does not have a constant size known at compile-time

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.

Resources