问题
Why do I need to make this closure variable mutable? The closure isn't returning anything, therefore nothing is being stored in the closure variable. This closure is only capturing a value from the environment and incrementing it.
fn main() {
let mut x = 1;
let mut y = || x = x + 1;
y();
println!("{}", x);
}
回答1:
Essentially, this is a consequence of one of Rust's soundness rules – you can't modify anything through a shared reference to a mutable reference. All the references in your chain of references need to be mutable for this to be possible.
Let's translate the closure in your example into roughly equivalent code using a struct:
struct Closure<'a> {
x: &'a mut i32,
}
impl Closure<'_> {
fn call(&mut self) {
*self.x += 1;
}
}
The closure captures x
by mutable reference – it has to to be able to modify it. When the closure is called, it receives self
by mutable reference – it has to to be able to mutate x
through the self
pointer.
Now if you want to call this closure, you need to make it mutable as well:
let mut x = 1;
let mut y = Closure { x: &mut x };
y.call();
If you don't make y
mutable, you can't pass a mutable reference to y
to the call()
method.
The reason for the soundness rule mentioned at the beginning is easy to see: If you could mutate through a shared reference to a mutable reference, it would be easy to write code with multiple players holding mutable references to the same memory location, which violates one of the fundamental rules about Rust references.
回答2:
You have the situation exactly backwards. Returning a value does not require storing anything in the closure. Capturing, on the other hand, does require storing something in the closure. In your case, y
needs to store a reference to x
. And since that reference is mutable, the closure needs to be mutable.
Here you can see the difference in size between a closure that returns something (but captures nothing) and a closure that captures, and a closure that captures even more things.
fn main() {
let mut a = 1;
let mut b = 1;
let mut c = 1;
let small = || {
return 10;
};
let mut bigger = || {
a = a + 1;
};
let mut biggest = || {
b = b + 1;
c = c + 1;
};
small();
bigger();
biggest();
println!("{}, {}, {}",
std::mem::size_of_val(&small),
std::mem::size_of_val(&bigger),
std::mem::size_of_val(&biggest)
);
}
Output:
0, 8, 16
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f48399e830f6a6e597338114ea30a409
And for completeness, here is a closure that captures a value, but doesn't mutate it. You can see that it doesn't need to be mutable.
fn main() {
let x = 1;
let y = || x;
println!("{}, {}", y(), std::mem::size_of_val(&y));
}
来源:https://stackoverflow.com/questions/59270277/when-do-i-need-to-make-a-closure-variable-mutable