如何将可变状态移动到闭包状态?

  • 本文关键字:状态 移动 闭包 rust
  • 更新时间 :
  • 英文 :


闭包的状态中有一些数据,但是如何使其可变?例如,我想要一个每次都返回递增值的计数器闭包,但它不起作用。我如何让它工作?

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].

正如错误消息所说:

无法在Fn闭包中分配给捕获的外部变量

相反,您需要一个FnMut关闭:

// In modern Rust, prefer returning `impl FnMut() -> i32`
fn counter() -> Box<dyn 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的行为吗?

也许闭包何时实现 Fn、FnMut 和 FnOnce?可以帮助提供一些背景信息。这是我直觉的一个方面,但还没有弄清楚如何最好地沟通。Finding Closure in Rust 中的这一部分似乎也相关:

在高层次上,self为实施者(即用户定义的用于实现特征的类型)提供了最大的灵活性,其次是&mut self&self最不灵活的。相反,&self为特征的使用者(即具有受特征限制的泛型的函数)提供了最大的灵活性,self最小。

简而言之,该特征定义表明,任何Fn闭包都可以在预期FnMut闭包的地方使用。这是有道理的,因为我们可以忽略FnMut可用的可变性。你不能走另一条路 - 你不能将不可变的引用变成可变的引用。

相关内容

  • 没有找到相关文章

最新更新