闭包在它们的状态中有一些数据,但我如何使它可变?例如,我想要一个每次都返回增量值的计数器闭包,但它不起作用。我如何让它发挥作用?
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]
的内容。
最佳答案
如错误信息所述:
cannot assign to captured outer variable in an
Fn
closure
相反,您需要一个 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
文档说:
A version of the call operator that takes a mutable receiver.
这允许闭包改变包含的状态。
顺便说一下,c
的显式类型不需要。
What confuses me, is that
pub trait Fn<Args>: FnMut<Args>
. Doesn't it mean thatFn
(what I used) should support behaviour ofFnMut
?
也许 When does a closure implement Fn, FnMut and FnOnce?可以帮助提供一些背景信息。这是我凭直觉得到的一个方面,但还没有想出如何最好地沟通。本节来自Finding Closure in Rust似乎也相关:
At a high-level
self
gives implementers (i.e. the types users define to implement the trait) the most flexibility, with&mut self
next and&self
the least flexible. Conversely,&self
gives consumers of the trait (i.e. functions with generics bounded by the trait) the most flexibility, andself
the least.
简而言之,特征定义表示任何 FnMut
闭包可以用作Fn
关闭。这是有道理的,因为我们可以简单地忽略可变性。你不能走另一条路 - 你不能将不可变引用变成可变引用。
关于rust - 如何将可变状态移动到闭包中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37949215/