Here is an example from Rust by Example:
pub trait Iterator {
// The type being iterated over.
type Item;
// `any` takes `&mut self` meaning the caller may be borrowed
// and modified, but not consumed.
fn any<F>(&mut self, f: F) -> bool where
// `FnMut` meaning any captured variable may at most be
// modified, not consumed. `Self::Item` states it takes
// arguments to the closure by value.
F: FnMut(Self::Item) -> bool {}
}
Why bother using FnMut
if the argument is taken by value, since the argument cannot be mutated anyways? In fact, why is FnMut
even allowed here? It seems only FnOnce
is permitted to do this:
It has been noted that Rust chooses how to capture variables on the fly without annotation. This is all very convenient in normal usage however when writing functions, this ambiguity is not allowed. The closure's complete type, including which capturing type, must be annotated. The manner of capture a closure uses is annotated as one of the following
trait
s:
Fn
: takes captures by reference (&T
)FnMut
: takes captures by mutable reference (&mut T
)FnOnce
: takes captures by value (T
)
The distinction between FnOnce
, FnMut
and Fn
is how the function accesses its environment (move, mutable reference, shared reference, respectively). It has nothing to do with accessing the function's arguments.
FnMut
is needed here, because the any
method may need to call the function multiple times.
There is a paragraph in the Rust book about the implementation of closures. It shows the differences in the self
argument, which essentially is a struct
that contains the environment.
Why bother use FnMut if the argument is taken by value, since the arg cannot be mutated anyways?
The example you linked is kind of incorrect, as the method definition should look like this:
fn any<F>(&mut self, mut f: F) -> bool // note the `mut f: F`
where F: FnMut(Self::Item) -> bool {}
(compare the std
implementation)
This change, however, does not change how the any
method can be used! The mut
is merely part of the variable binding (which is only important for the method impl) and not part of the type. Taking something by value gives us complete control over the variable -- if we want to mutate the variable, we can do so, but we have to bind it mutably.
In fact, why is FnMut even allowed here?
You can have trait bounds that would allow all kinds of operations with a type, even if you can't use those operations due to lacking access to the variable. See:
fn foo<T: Iterator<Item=i32>>(it: &T) {}
This is valid, but not useful, because as soon as you want to do something usable with the iterator (like calling next
):
it.next();
You will get a compiler error, since you can't call a &mut self
method on an immutable borrow. So the example you linked only works, because the function body doesn't use the functionality of FnMut
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With