为什么我需要将这个闭包变量变成可变的?因为闭包没有返回任何东西,因此在闭包变量中没有存储任何内容。这个闭包只是从环境中捕获一个值并对其进行递增操作。
fn main() {
let mut x = 1;
let mut y = || x = x + 1;
y();
println!("{}", x);
}
为什么我需要将这个闭包变量变成可变的?因为闭包没有返回任何东西,因此在闭包变量中没有存储任何内容。这个闭包只是从环境中捕获一个值并对其进行递增操作。
fn main() {
let mut x = 1;
let mut y = || x = x + 1;
y();
println!("{}", x);
}
struct Closure<'a> {
x: &'a mut i32,
}
impl Closure<'_> {
fn call(&mut self) {
*self.x += 1;
}
}
闭包使用可变引用捕获变量 x
,以便能够修改它。当闭包被调用时,它通过可变引用接收 self
,以便可以通过 self
指针改变 x
。
现在,如果你想调用这个闭包,你需要使它也是可变的:
let mut x = 1;
let mut y = Closure { x: &mut x };
y.call();
如果您不将y
变为可变的, 您就不能将一个可变引用传递给call()
方法。
上述类型安全规则的原因很容易理解: 如果您可以通过对可变引用的共享引用进行变更,那么很容易编写出多个玩家持有对同一内存位置的可变引用的代码,这违反了Rust引用的基本规则之一。
你的情况完全相反。返回一个值不需要在闭包中存储任何东西。而捕获则需要在闭包中存储一些东西。在你的情况下,y
需要存储对 x
的引用。由于该引用是可变的,因此闭包需要是可变的。
在这里,你可以看到一个仅返回值(但未捕获任何内容)、一个捕获了一些内容、以及一个捕获了更多内容的闭包之间的大小差异。
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)
);
}
输出:
0, 8, 16
为了完整起见,这里有一个捕获值但不改变它的闭包。你可以看到它不需要可变性。
fn main() {
let x = 1;
let y = || x;
println!("{}, {}", y(), std::mem::size_of_val(&y));
}