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`