This error occurs because the function or trait you are passing the closure to requires it to be callable multiple times (Fn), but your closure captures a variable by move, making it callable only once (FnOnce). To fix it, change the capture mode to borrow the variable (using & or &mut) instead of moving ownership, or restructure the code so the variable doesn't need to be moved into the closure.
The most common cause is capturing a non-Copy type (like a String or a custom struct) by value. When you do this, the closure takes ownership of that value. If the closure is called a second time, the value is already gone, violating the Fn contract.
Here is a practical example of the error and the fix:
fn apply_twice<F>(f: F, x: i32)
where
F: Fn(i32) -> i32, // Requires Fn (callable multiple times)
{
let result1 = f(x);
let result2 = f(x); // Fails if f is FnOnce
println!("Results: {}, {}", result1, result2);
}
fn main() {
let data = String::from("hello");
// ERROR: Captures `data` by move. After the first call, `data` is gone.
// This closure only implements FnOnce, but `apply_twice` needs Fn.
// let bad_closure = |x| { println!("{} {}", data, x); };
// apply_twice(bad_closure, 1);
// FIX 1: Borrow the data instead of moving it.
// This closure implements Fn because it only borrows `data`.
let good_closure = |x| { println!("{} {}", data, x); };
apply_twice(good_closure, 1);
// FIX 2: If you must modify the captured variable, use a mutable reference.
let mut counter = 0;
let mut_counter_closure = |x| {
counter += 1;
println!("Count: {}, Input: {}", counter, x);
};
// Note: This requires the function signature to accept FnMut instead of Fn
}
If you specifically need to move ownership into the closure (e.g., to consume a resource), you cannot use a function expecting Fn. You must change the function signature to accept FnOnce instead, or use a std::cell::RefCell or std::sync::Mutex to wrap the data if you need interior mutability.
For most cases, simply ensuring you capture by reference (&data) or mutable reference (&mut data) resolves the issue immediately. If the variable is a Copy type (like i32), Rust automatically copies it, so the closure naturally implements Fn. The error almost always points to a non-Copy type being moved by mistake.