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

标签 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] 的内容。

最佳答案

如错误信息所述:

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 that Fn (what I used) should support behaviour of FnMut?

也许 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, and self the least.

简而言之,特征定义表示任何 FnMut闭包可以用作Fn关闭。这是有道理的,因为我们可以简单地忽略可变性。你不能走另一条路 - 你不能将不可变引用变成可变引用。

关于rust - 如何将可变状态移动到闭包中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37949215/

相关文章:

memory-management - 如何检测某个类型何时需要调用 'drop'?

rust - 变量绑定(bind) : moving a &mut or borrowing the referent?

rust - 如何同时声明多个可变变量?

real-time - 我如何在 Rust 中进行实时编程?

vector - 惯用地将空格分隔的字符串解析为不同类型元组的 Vec

rust - 如何将 (String, String) 元组上的迭代器转换为 (&str, &str) 的迭代器?

rust - 如何将 Entry API 与仅在 Entry 为空时才构建的昂贵 key 一起使用?

string - 如何将字符串拆分为第一个字符和其余字符?

rust - 我可以用来允许访问集合的中间元素的最一般特征是什么?

rust - 如何找到用于引导 rustc master 的 rustc 提交