Why are predicates for Rust iterator's FnMut and not Fn?

475 Views Asked by At

Looking at the predicates like skip_while and take_while they're

skip_while<P>(self, predicate P) -> ...
  where Self: Sized, P: FnMut(&Self::Item) -> bool;

If a predicate is just returning true or false, and not modifying the values, why does it have to be FnMut and not Fn (like Fn(&Self::Item) -> bool)?

1

There are 1 best solutions below

1
mcarton On

The Mut in FnMut means that the predicate can have a mutable state. It says nothing about the parameters.

Additionaly, FnMut is a super-trait of Fn, so you can also pass an Fn where FnMut is accepted.

As a silly example, consider this closure that stores a state (hence is FnMut, but not Fn), but cannot modify the elements in the iterator:

fn main() {
    let v = vec![1, 2, 3, 4, 0, 5, 6, 7];

    println!("{:?}", v.iter().skip_while(|&&v| v != 0).collect::<Vec<_>>());

    let mut state = false;
    let one_after_zero = |&&v: &&u32| {
        if state {
            false
        } else if v == 0 {
            state = true;
            true
        } else {
            true
        }
    };

    println!("{:?}", v.iter().skip_while(one_after_zero).collect::<Vec<_>>());
}

(Permalink to the playground)

Output:

[0, 5, 6, 7]
[5, 6, 7]