闭包在其状态中有一些数据,但我如何使其变为可变?例如,我想要一个计数器闭包,每次都返回递增的值,但它不起作用。我如何使它工作?
fn counter() -> Box<Fn() -> i32> {
let mut c: i32 = 0;
Box::new(move || {
c += 1;
c
})
}
fn main() {
let mut a = counter();
let mut b = counter();
println!("{:?}", [a(), a(), a(), b(), b(), a()]);
}
错误(和警告)我得到了:
error: cannot assign to captured outer variable in an `Fn` closure
c += 1;
^~~~~~
help: consider changing this closure to take self by mutable reference
Box::new(move || {
c += 1;
c
})
我希望它输出类似[1, 2, 3, 1, 2, 4]
的内容。
答案 0 :(得分:10)
正如错误消息所示:
无法在
中分配给捕获的外部变量Fn
闭包
相反,你想要一个FnMut
闭包:
fn counter() -> Box<FnMut() -> i32> {
let mut c = 0;
Box::new(move || {
c += 1;
c
})
}
fn main() {
let mut a = counter();
let mut b = counter();
let result = [a(), a(), a(), b(), b(), a()];
println!("{:?}", result);
assert_eq!([1, 2, 3, 1, 2, 4], result);
}
正如FnMut
文档所说:
一个带有可变接收器的调用操作符的版本。
这允许闭包改变包含的状态。
顺便说一句,不需要c
的显式类型。
令我困惑的是
pub trait Fn<Args>: FnMut<Args>
。这不是说Fn
(我使用过的)应该支持FnMut
的行为吗?
或许When does a closure implement Fn, FnMut and FnOnce?可以帮助提供一些背景信息。这是我直观的一个方面,但还没有弄清楚如何最好的沟通。 Finding Closure in Rust的这一部分似乎也很相关:
在高级别
self
给予实施者(即用户定义以实现特征的类型)最大的灵活性,其次是&mut self
,&self
最不灵活。相反,&self
给予消费者特征(即具有特征限制的泛型的功能)最灵活,并且self
最少。
简而言之,该特征定义表明任何FnMut
闭包都可以用作Fn
闭包。这是有道理的,因为我们可以简单地忽略可变性。你不能走另一条路 - 你不能将一个不可变的引用变成一个可变的引用。