Reputation: 2181
I have a mutable string variable, and an immutable variable bound to a mutable reference to the mutable string variable.
let mut string = String::from("test");
let variable: &mut String = &mut string;
variable.push_str(" test");
string.push_str(" test");
This fails:
error[E0499]: cannot borrow `string` as mutable more than once at a time
--> src/main.rs:5:5
|
3 | let variable: &mut String = &mut string;
| ------ first mutable borrow occurs here
4 | variable.push_str(" test");
5 | string.push_str(" test");
| ^^^^^^ second mutable borrow occurs here
6 | }
| - first borrow ends here
push_str
?push_str
on the second variable and not on the first?Upvotes: 3
Views: 1521
Reputation: 128061
You're getting this error because mutable borrowing is exclusive:
let mut string = String::from("test")
let variable = &mut string;
Here you create a mutable reference to a variable; because mutable references imply exclusive access, it is now impossible to access the original variable, because otherwise you would be violating aliasing guarantees.
Consider this:
let mut string = String::from("test");
{
let variable = &mut string;
variable.push_str(" test");
}
string.push_str(" test");
This code will compile and work as intended, because the mutable reference goes out of scope before the original variable is accessed again.
You can read more about this in the Rust book (see this link for the second edition of the book).
As for why you can call the mutating method on a non-mut variable, well, it is possible simply because the push_str()
method accepts its receiver by &mut
; if you already have &mut
then it is used directly, but if you don't have one, then Rust will automatically try to create one for you, which is not possible if the variable is not mut
:
let mut string = String::from("test");
string.push_str("test");
// equivalent to:
String::push_str(&mut string, "test"); // won't work if `string` is not `mut`
let variable = &mut string;
variable.push_str("test");
// [almost] equivalent to:
String::push_str(variable, "test"); // works because `variable` is already `&mut`
I wrote "almost" in the example above because in this case there is another step called reborrowing which basically ensures that the mutable reference can be used again after this call instead of being moved into the function call, but it doesn't really matter for this answer.
Upvotes: 5
Reputation: 1799
The Rust Book explains question 1 pretty well:
let mut x = 5; let y = &mut x;
y
is an immutable binding to a mutable reference, which means that you can’t bind 'y' to something else (y = &mut z
), buty
can be used to bindx
to something else (*y = 5
).
Basically, variable.push_str(" test");
is mutating the String
that variable
references, but it does not affect variable
(i.e. the binding) itself.
The compiler error should explain question 2.
Upvotes: 3