error[E0373]: closure may outlive the current function, but it borrows `val`, which is owned by the current function

クロージャのキャプチャ変数のライフタイムが、クロージャの境界を順守できないほど短い。

パターン

パターン A

クロージャが戻り値

問題のクロージャが関数の戻り値になっているパターン。

サンプル

以下では、関数 get_lambda の戻り値がクロージャであり、それが変数 val をキャプチャしている。しかし、val はローカル変数のため、関数の呼出後は有効でなくなっている。


fn get_lambda() -> impl Fn() {
    let val = 42;
    || { dbg!(val); }
}

error[E0373]: closure may outlive the current function, but it borrows `val`, which is owned by the current function
 --> src\lib.rs:3:5
  |
3 |     || { dbg!(val); }
  |     ^^        --- `val` is borrowed here
  |     |
  |     may outlive borrowed value `val`
  |
note: closure is returned here
 --> src\lib.rs:3:5
  |
3 |     || { dbg!(val); }
  |     ^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `val` (and any other referenced variables), use the `move` keyword
  |
3 |     move || { dbg!(val); }
  |     ++++

パターン B

クロージャが引数

問題のクロージャが関数の引数になっているパターン。

サンプル

以下では、関数 call_lambda の引数がクロージャであり、それが変数 val をキャプチャしている。しかし、val はローカル変数のため、'static つきの引数型からは参照できない。


fn test() {
    let val = 42;
    call_lambda(|| { dbg!(val); });
}

fn call_lambda(_f: impl Fn() + 'static) {}

error[E0373]: closure may outlive the current function, but it borrows `val`, which is owned by the current function
 --> src\lib.rs:3:17
  |
3 |     call_lambda(|| { dbg!(val); });
  |                 ^^        --- `val` is borrowed here
  |                 |
  |                 may outlive borrowed value `val`
  |
note: function requires argument type to outlive `'static`
 --> src\lib.rs:3:5
  |
3 |     call_lambda(|| { dbg!(val); });
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `val` (and any other referenced variables), use the `move` keyword
  |
3 |     call_lambda(move || { dbg!(val); });
  |                 ++++

解決策

エラーメッセージの help にある通り、クロージャに move を指定する。

すると、クロージャはキャプチャ変数を参照する代わりに、クロージャ自身にキャプチャ変数を移動してその内容を使うようになる。これにより、クロージャとキャプチャ変数のライフタイムは必ず一致するようになる。