我有以下代码(playground):

struct A {
    pub vec: Vec<u64>,
}

impl A {
    fn perform_for_all<F: Fn(&mut u64)>(&mut self, f: F) {
        for mut i in &mut self.vec {
            f(i);
        }
    }
}
fn main() {
    let mut a = A {
        vec: vec![1, 3, 44, 2, 4, 5, 6],
    };

    let mut done = false;

    a.perform_for_all(|v| {
        println!("value: {:?}", v);
        done = true;
    });

    if !done {
        a.perform_for_all(|v| {
            println!("value {:?}", v);
        });
    }
}

出现以下错误:

error[E0594]: cannot assign to `done`, as it is a captured variable in a `Fn` closure
  --> src/main.rs:21:9
   |
21 |         done = true;
   |         ^^^^^^^^^^^ cannot assign
   |
help: consider changing this to accept closures that implement `FnMut`
  --> src/main.rs:19:23
   |
19 |       a.perform_for_all(|v| {
   |  _______________________^
20 | |         println!("value: {:?}", v);
21 | |         done = true;
22 | |     });
   | |_____^

我有一个加载对象列表和数据库中的对象列表.我需要一个函数,它接受闭包并在加载的对象上执行它,如果列表中没有对象,则在数据库中的对象列表上执行它.

这个函数看起来像:

pub fn perform_for_match_with_mark<F>(&mut self, mark: MatchMark, f: F)
where
    F: Fn(&mut GameMatch),
{
    self.perform_for_all_matches(
        |m| {
            // runtime list
            if let Game::Match(ref mut gm) = *m {
                if gm.match_stamp().mark == mark {
                    f(gm);
                }
            }
        },
        None,
    );
    // if we have called `f` above - don't execute lines below.
    let tx = self.match_tx.clone();
    GamesDatabase::perform_for_match_with_mark(mark, |ms| {
        // database
        self.perform_for_all_matches(
            |m| {
                if let Game::Match(ref gm) = *m {
                    if gm.match_stamp().id == ms.id {
                        f(&mut GameMatch::new_with_match_stamp(
                            tx.clone(),
                            ms.clone(),
                            gm.needs_server_set,
                            gm.server_id,
                        ))
                    }
                }
            },
            None,
        );
    });
}

只有在运行时列表中找不到对象时,才能对数据库中的对象进行操作.这就是为什么我决定创建一个变量,它表示"我们已经在列表中找到了这些对象,请别管数据库".

推荐答案

perform_for_all函数改为FnMut而不是Fn:

fn perform_for_all<F>(&mut self, mut f: F)
where
    F: FnMut(&mut u64),
{
    for mut i in &mut self.vec {
        f(&mut i);
    }
}

As Peter said,有一些编译器的魔力正在发生.

Fn::call的签名是:

extern "rust-call" fn call(&self, args: Args) -> Self::Output

这是对self的不可变引用,这就是为什么不能修改任何捕获的变量.

FnMut::call_mut的签名允许你变异变量,因为它需要&mut self:

extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output

通过将闭包从Fn更改为FnMut,可以允许它修改捕获的变量,因为传递给它的引用是可变的.

Rust相关问答推荐

错误[E0793]具体何时发生:对打包字段的引用未对齐触发?

什么样的 struct 可以避免使用RefCell?

如何装箱生命周期相关联的两个对象?

在Rust中,在实现特征`Display`时,如何获取调用方指定的格式?

如何编写一个以一个闭包为参数的函数,该函数以另一个闭包为参数?

无法从流中读取Redis请求

Tokio_Postgres行上未显示退回特性的生存期,且生命周期 不够长

获取与父字符串相关的&;str的原始片段

如何防止Cargo 单据和Cargo 出口发布( crate )项目

如何使用reqwest进行异步请求?

.在 Rust 模块标识符中

当我try 使用 SKI 演算中的S I I实现递归时,为什么 Rust 会失败?

Rust:为什么 Pin 必须持有指针?

一旦令牌作为文字使用,声明宏不匹配硬编码值?

使用 lalrpop 在 rust 中解析由 " 引用的字符串

如何在 Rust 中将枚举变体转换为 u8?

意外的正则表达式模式匹配

为什么可以从闭包中返回私有 struct

当值是新类型包装器时,对键的奇怪 HashMap 生命周期要求

为什么我不能将元素写入 Rust 数组中移动的位置,但我可以在元组中完成