error: captured variable cannot escape `FnMut` closure body

FnMut クロージャからキャプチャ変数が流出した。

概要

FnMut 形式のクロージャで可変変数をキャプチャした場合、その変数の参照はクロージャの外部に流出させられない。これにより、過去のクロージャの呼出で流出した参照の借用中に、再びクロージャが実行され、借用と更新が競合するのを予防している。

サンプル

以下では、変数 counter への参照がクロージャから流出している。


fn main() {
    let mut counter = 1;
    use_fn_mut(|| {
        counter += 1;
        &counter
    });
}

fn use_fn_mut<'a, F>(_: F)
where
    F: FnMut() -> &'a i32 + 'a
{}

error: captured variable cannot escape `FnMut` closure body
 --> src\main.rs:5:9
  |
2 |     let mut counter = 1;
  |         ----------- variable defined here
3 |     use_fn_mut(|| {
  |                 - inferred to be a `FnMut` closure
4 |         counter += 1;
  |         ------- variable captured here
5 |         &counter
  |         ^^^^^^^^ returns a reference to a captured variable which escapes the closure body
  |
  = note: `FnMut` closures only have access to their captured variables while they are executing...
  = note: ...therefore, they cannot allow references to captured variables to escape

解決策

FnMut の代わりに FnOnce を使えば、一度きりの実行が保証されエラーにならない。


fn main() {
    let mut counter = 1;
    use_fn_once(|| {
        counter += 1;
        &counter
    });
}

fn use_fn_once<'a, F>(_: F)
where
    F: FnOnce() -> &'a i32 + 'a
{}