Let's say I have this code:
let mut s = "hi".to_string();
let c = || s.push_str(" yo");
c();
It doesn't compile and generates this error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src\test.rs:120:9
|
119 | let c = || s.push_str(" yo");
| - - calling `c` requires mutable binding due to mutable borrow of `s`
| |
| help: consider changing this to be mutable: `mut c`
120 | c();
| ^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0596`.
error: could not compile `test` due to previous error
Why c();
cannot borrow as mutable? It cannot borrow what as mutable? c
? In order to make it work, I have to change it to:
let mut s = "hi".to_string();
let mut c = || s.push_str(" yo");
c();
But here I'm just defining a closure c
. I'll not modify it, like c = || x;
. Why must define it as let mut c
?
But here I'm just defining a closure
c
. I'll not modify it, likec = || x;
. Why must define it as letmut c
?
Because a closure is fundamentally a structure, each captured item being a member of that structure.
So your code is roughly equivalent to this:
struct S<'a>(&'a mut String);
impl S<'_> {
fn call(&mut self) {
self.0.push_str("yo");
}
}
fn main() {
let mut s = "hi".to_string();
let c = S(&mut s);
c.call();
}
And that fails to compile with more or less the same error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src/main.rs:14:5
|
13 | let c = S(&mut s);
| - help: consider changing this to be mutable: `mut c`
14 | c.call();
| ^^^^^^^^ cannot borrow as mutable
Now you might object that that's because I defined fn call(&mut self)
, but if you don't you get the internal part of the same error:
error[E0596]: cannot borrow `*self.0` as mutable, as it is behind a `&` reference
--> src/main.rs:8:9
|
7 | fn call(&self) {
| ----- help: consider changing this to be a mutable reference: `&mut self`
8 | self.0.push_str("yo");
| ^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
That is you can't modify an &mut
through an &
. Because if you did you could create multiple &
s to the same &mut
through which you could modify the pointee, and that would essentially give you multiple &mut
.
Which is not allowed by Rust's semantics:
At any given time, you can have either one mutable reference or any number of immutable references.