Confusing behavior on when to dereference the mutable reference - rust

I have a function that takes the mutable reference of the string and appends some text.
fn append_str(s: &mut String) {
s.push_str(" hi");
}
Suppose I have a string.
let mut s: String = "hi".to_string();
If I create the mutable reference to s and pass it to append_str, it compiles without a problem.
let mut ss = &mut s;
append_str(&mut ss);
However, if I expliclty define ss with &mut String, it does not compile.
let ss: &mut String = &mut s;
append_str(&mut ss);
it shows following compiler error.
|
80 | let ss: &mut String = &mut s;
| -- help: consider changing this to be mutable: `mut ss`
81 | append_str(&mut ss);
| ^^^^^^^ cannot borrow as mutable
One thing funny is that if I dereference it, then it works.
let ss: &mut String = &mut s;
append_str(&mut *ss); // OK
What is the reason that we have to explicitly dereference in this case?
One more question: Why do we have to specify mut to the reference if we want to pass it to the function?
let ss = &mut s;
append_str(&mut ss); // ERROR

ss is a reference already, so &mut ss gives you (mutable) reference to (mutable) reference; if you have ss, you should call append_str with it directly: append_str(ss).
It is only when you incorrectly take a mutable reference to ss, you need to declare it as mut ss. The normal use case for something like that is to pass it to a function that actually accepts x: &mut &mut String and uses something like *x = &mut some_other_string to make ss refer to a different reference to string. In your case the "fixed" code with mut compiles because the compiler automatically dereferences the double-reference for you.

Related

Borrowed value of RefCell does not live long enough

I created two example codes, one using references of a Box and the other using borrow_mut of a RefCell and they don't work the same, to my surprise.
use std::cell::RefCell;
#[derive(Debug)]
struct A {
a: usize,
}
fn main() {
let m;
let mut n = Box::new(A{a:5});
{let a = &mut n; m = &mut a.a;}
*m = 6;
println!("{}", m);
println!("{:?}", n);
let mm;
let mut nn = RefCell::new(A{a:5});
{let mut aa = nn.borrow_mut(); mm = &mut aa.a;}
*mm = 6;
println!("{:?}", mm);
println!("{:?}", nn);
}
I'm getting an error saying the aa borrowed value does not live long enough. &mut aa.a should be &mut usize so nothing to do with a RefCell and should work just like the Box example. Why am I getting this error?
The problem is that while the borrow &mut n is just a pure reference, nn.borrow_mut() is not. It returns a RefMut that implements Drop - because it needs to mark the RefCell as no longer borrowed after it is dropped. Therefore, the compiler can extend the lifetime of &mut n as it doesn't do anything when dropped, but it cannot do so for nn.borrow_mut() because it alters the behavior of the program.

Assign mutable reference to immutable reference

This code doesn't compile. But it fails on the last line marked Err, not the line marked Ok. Why can we assign a mutable reference to an immutable reference type but not use it after the assignment?
fn main() {
let mut x = 10;
let mut y = 20;
let mut r = &x;
r = &mut y; //Ok
*r = 30; //Err
}
Why can we ... not use it after the assignment?
The variable r is an immutable reference of type &i32; it does not have mutable access to the referenced value. So it makes sense the compiler would reject your attempt to assign through it.
Why can we assign a mutable reference to an immutable reference type ...?
Why wouldn't you be able to downgrade a mutable reference into an immutable one? The latter is a strict subset of the former. If you were asking about the technicalities instead of the practicalities, its because &mut T to &T is a supported coercion.
If we add explicit types to your code as inferred by the compiler:
fn main() {
let mut x: i32 = 10;
let mut y: i32 = 20;
let mut r: &i32 = &x;
r = &mut y; //Ok
*r = 30; //Err
}
We see that r has type &i32 and not &mut i32, so of course we can't use r to modify the referenced value.
Why can we still do r = &mut y? Simply because we can always use a &mut reference anywhere a & reference is expected (because &mut T implements Deref<Target=T>, allowing coercion to happen).

Why does the compiler error complain about multiple mutable references not dangling reference?

I am trying to understand what exactly happens when functions reborrow mutable references.
fn main() {
let mut a = String::new();
let mut b = String::new();
let aa = &mut a;
let c = my_fun(aa, &mut b);
let d = &mut a;
println!("{}", c);
}
fn my_fun<'b>(x: &'b mut String, y: &'b mut String) -> &'b mut String { y }
From my understanding the my_fun reborrows aa as &*aa whose scope would be the my_fun. But due to the lifetime bound I created in the function signature the reborrow should live at least as long as &mut b exist. So the println force the reborrow to live until it.
Shouldn't this be throwing an error of use after free because the anonymous reborrow has only scope inside my_fun? Outside of this function this reference shouldn't be valid.
But the error I get is:
error[E0499]: cannot borrow `a` as mutable more than once at a time
--> src/main.rs:7:13
|
5 | let aa= &mut a;
| ------ first mutable borrow occurs here
6 | let c = my_fun(aa, &mut b);
7 | let d = &mut a;
| ^^^^^^ second mutable borrow occurs here
8 | println!("{}", c);
| - first borrow later used
which would have made sense if the mutable reference was merely copied instead of reborrowed inside the function.
From my understanding the my_fun reborrows aa as &*aa whose scope would be the my_fun.
It's not quite that.
Let's backtrack a bit: why reborrowing?
There is a fundamental difference between &T and &mut T: &T is Copy, whereas &mut T is not even Clone. The result is that &mut T can only be moved and therefore a call such as:
let x: &mut T = /*...*/;
func(x);
Would result in x being unusable after the call. The work-around would then be to introduce a temporary:
let x: &mut T = /*...*/;
let tmp = &mut *x;
func(tmp);
This temporary would re-borrow the pointee of x, and be consumed by func.
And... that's re-borrowing! The compiler has this "temporary" creation built-in purely for ergonomics!
With that in mind, let's go back to:
From my understanding the my_fun reborrows aa as &*aa whose scope would be the my_fun.
Lifetimes are generally more a range than a point, and this is true here.
The lifetime of tmp in my example above is constrained in 2 ways:
It cannot be greater than that of x.
It cannot be less than that of func.
Which is another way of saying that it can be anything in between those bounds.
I believe you're overthinking "reborrowing" here.
The lifetime requirements you applied say that the thing being referenced by the return value will have at least the lifetime of the things being referenced by the parameters. That's true (and if it weren't provably true, this wouldn't compile). So there is no dangling reference possible.
There isn't a separate "reborrowed" reference. Borrowing is bookkeeping inside the compiler to keep track of lifetimes. There is no let x = &*aa step that actually occurs or is even particularly implied. This isn't like reference counting where memory actually changes at runtime.
Inside of my_fun, y is a reference that's scoped to the function. But the return value is scoped to the caller. (Functions would be impossible to use if this weren't true, having nothing to do with &mut.)

Why does a variable holding the result of Vec::get_mut not need to be mutable?

I have the following code:
fn main() {
let mut vec = Vec::new();
vec.push(String::from("Foo"));
let mut row = vec.get_mut(0).unwrap();
row.push('!');
println!("{}", vec[0])
}
It prints out "Foo!", but the compiler tells me:
warning: variable does not need to be mutable
--> src/main.rs:4:9
|
4 | let mut row = vec.get_mut(0).unwrap();
| ----^^^
| |
| help: remove this `mut`
Surprisingly, removing the mut works. This raises a few questions:
Why does this work?
Why doesn't this work when I use vec.get instead of vec.get_mut, regardless of whether I use let or let mut?
Why doesn't vec work in the same way, i.e. when I use let vec = Vec::new(), why can't I call vec.push()?
vec.get_mut(0) returns an Option<&mut String>, so when you unwrap that value you will have a mutable borrow of a String. Remember, that a let statement's left side is using pattern matching, so when your pattern is just a variable name you essentially say match whatever is on the right and call it name. Thus row matches against &mut String so it already is mutable.
Here's a much simpler and more straightforward example to illustrate the case (which you can try in the playground):
fn main() {
let mut x = 55i32;
dbg!(&x);
let y = &mut x; // <-- y's type is `&mut i32`
*y = 12;
dbg!(&x);
}

Mysterious borrow scope extension

Why does the compiler reject this code:
struct S<'a> {
i: i32,
r: &'a i32,
}
fn main() {
let mut s = S{i: 0, r: &0};
{
let m1 = &mut s;
m1.r = &m1.i;
}
let m2 = &mut s;
}
The error is: "cannot borrow s as mutable more than once at a time" (first borrow: m1, second borrow: m2).
Why is the first borrow of s still alive after m1 goes out of scope?
I read about borrow scope extension beyond the scope of the original borrower. However, this always seemed to involve another borrower outside the scope of the original borrower that "took over" the original borrow, e.g. this code fails with the exact same error, which is clear to me:
fn main() {
let mut s = 0;
let r: &mut i32;
{
let m1 = &mut s;
r = m1;
}
let m2 = &mut s;
}
In the first example, if I replace m1.r = &m1.i; with m1.r = &dummy; (dummy defined as some &i32) or with let dummy = &m1.i;, the code compiles. The error occurs only if I store a reference to a field in another field of the borrowed struct. I don't see why this should extend the borrow beyond its scope.
My best guess as to what is wrong with the code is:
s.r's original lifetime is the whole of main,
when I assign a reference to m1.r it has to be that original lifetime, but &m1.i is only valid for as long as m1 lives.
But I might be wrong (the error message would be misleading then).
First note that
let mut s = S{i: 0, r: &0};
{
s.r = &s.i;
}
let m2 = &mut s;
Gives
cannot borrow `s` as mutable because `s.i` is also borrowed as immutable
Hopefully this should be clear - if a struct self-borrows then it is borrowed. This points out why any self-borrowing structure is basically useless - it cannot be moved (invalidating its own pointer) nor can and mutable reference be taken to it.
Next one needs to understand that immutable references from mutable references count as borrows into the mutable reference, so extend it. For example
let mut v = ();
let r1 = &(&mut v);
let r2 = &v;
gives
cannot borrow `v` as immutable because it is also borrowed as mutable
It's not clear if this is legally able to be a new borrow into the original structure, but it as-yet does not act as such.

Resources