error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
クロージャが期待されるトレイトを実装していなかった。
クロージャ用のトレイトには FnOnce, FnMut, Fn の三種類があり、後に行くほど要件が追加されていく。そして、クロージャが期待されたトレイトを実装しないとエラーになる。
Fn への不適合
キャプチャした変数の編集があると、Fn に適合しなくなる。
以下では、クロージャがキャプチャ変数 val を編集している。
fn main() {
let mut val = 0;
let closure = || { val += 1;};
callback(closure);
}
fn callback<F: Fn()>(f: F) {
f();
}
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> src\main.rs:3:19
|
3 | let closure = || { val += 1;};
| ^^ --- closure is `FnMut` because it mutates the variable `val` here
| |
| this closure implements `FnMut`, not `Fn`
4 | callback(closure);
| -------- ------- the requirement to implement `Fn` derives from here
| |
| required by a bound introduced by this call
|
note: required by a bound in `callback`
--> src\main.rs:7:16
|
7 | fn callback<F: Fn()>(f: F) {
| ^^^^ required by this bound in `callback`
Fn と FnMut への不適合 (キャプチャした変数のムーブ)
キャプチャした変数をムーブすると、Fn や FnMut に適合しなくなる。
ムーブはトレイト Copy を実装している型では発生しない。
そのため、同じようなコードでも、このエラーが発生するかはキャプチャ変数次第である。
以下では、クロージャがキャプチャした変数 val をムーブしている。
fn main() {
let val = Val();
let closure = || { move_arg(val); };
callback(closure);
}
fn move_arg(arg: Val) {
_ = arg;
}
fn callback<F: Fn()>(f: F) {
f();
}
struct Val();
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src\main.rs:3:19
|
3 | let closure = || { move_arg(val); };
| ^^ --- closure is `FnOnce` because it moves the variable `val` out of its environment
| |
| this closure implements `FnOnce`, not `Fn`
4 | callback(closure);
| -------- ------- the requirement to implement `Fn` derives from here
| |
| required by a bound introduced by this call
|
note: required by a bound in `callback`
--> src\lib.rs:11:16
|
11 | fn callback<F: Fn()>(f: F) {
| ^^^^ required by this bound in `callback`
Fn と FnMut への不適合 (キャプチャした可変参照のムーブ)
これは前のパターンの可変参照版である。
見落としがちだが、可変参照型もトレイト Copy を実装していない。
そのため、キャプチャした可変参照を他の関数などへ渡すとエラーになる。
以下では、クロージャが可変参照 val_mut をムーブしている。
fn main() {
let mut val = 0;
let val_mut = &mut val;
let closure = || { with_mut(val_mut); };
callback(closure);
}
fn with_mut(arg: &mut i32) {
_ = arg;
}
fn callback<F: Fn()>(f: F) {
f();
}
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> src\main.rs:4:19
|
4 | let closure = || { with_mut(val_mut); };
| ^^ ------- closure is `FnMut` because it mutates the variable `*val_mut` here
| |
| this closure implements `FnMut`, not `Fn`
5 | callback(closure);
| -------- ------- the requirement to implement `Fn` derives from here
| |
| required by a bound introduced by this call
|
note: required by a bound in `callback`
--> src\main.rs:12:16
|
12 | fn callback<F: Fn()>(f: F) {
| ^^^^ required by this bound in `callback`