We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Closures and Iterators step 2 of 28
Fn, FnMut, FnOnce: the closure hierarchy
Repair three helpers and use them to double a list, total the doubled values, and build a report. Keep the supplied public signatures and trait bounds:
pub fn each<F: Fn(i64) -> i64>(nums: &[i64], f: F) -> Vec<i64>
pub fn tally<F: FnMut(i64)>(nums: &[i64], f: F)
pub fn finish<F: FnOnce() -> String>(f: F) -> String
pub fn run_three(nums: Vec<i64>) -> (i64, Vec<i64>, String)
eachcallsfonce per input value, in order, and returns the results.tallycallsfonce per input value, in order, for its side effects.finishcallsfexactly once and returns its string unchanged.
In run_three, call each with a doubling closure. Pass the doubled vector
to tally with a closure that adds each value to a captured i64 counter.
Then create the report string and pass it to finish in a closure that moves
the string out when called. Return (total, doubled, report).
The report is exactly "n=<count> total=<total>", with one space between the
fields and no newline. The count is the input length. Preserve input order
and duplicates; negative values are allowed. Inputs are chosen so each
doubling and each intermediate total fit in i64.
For [1, 2, 3], return (12, [2, 4, 6], "n=3 total=12").
For [], return (0, [], "n=0 total=0").
What the three traits allow
| Bound | How the call accesses the closure | What the helper may do |
|---|---|---|
FnOnce |
Consumes self |
Call the owned closure once. |
FnMut |
Borrows &mut self |
Call repeatedly through mutable access. |
Fn |
Borrows &self |
Call repeatedly through shared access. |
Every closure implements FnOnce. A closure implementing Fn also implements
FnMut and FnOnce; one implementing FnMut also implements FnOnce.
The traits describe available ways to call it, not how many calls a function
actually makes. These helpers' descriptions specify their call counts.
Moving a non-Copy value out of a capture makes a closure FnOnce-only.
Mutating an ordinarily captured counter requires FnMut. Reading captures
can use Fn. Interior mutability is an important exception to the shorthand
"Fn means no state changes": an Fn closure can update a Cell, for example.
Fn alone also promises neither thread safety nor independence from call
order; concurrency needs appropriate Send and Sync bounds.
In your own APIs, choose a bound that permits the calls you need without
unnecessarily restricting callers. For this exercise, keep each's Fn
bound even though its loop could also be implemented with FnMut.
Capturing by value is different from moving out
move controls how a closure captures values. It does not by itself make
the closure FnOnce-only. This complete example owns a String but only
borrows it during each call, so the closure implements Fn:
fn twice<F: Fn() -> usize>(f: F) -> (usize, usize) {
(f(), f())
}
fn main() {
let name = String::from("Rust");
let length = move || name.len();
assert_eq!(twice(length), (4, 4));
}
By contrast, move || label returns its captured String by value. The
first call moves that string out, so that closure cannot be called again.
Copying a captured Copy value out does not have this restriction.
Repair the starter
In tally, the owned parameter binding must be mut f: F so the loop can
call it through mutable access. Without that change, the compiler reports
E0596. Parameter mutability affects the local binding, not the function type.
In finish, the first call consumes f, and the attempted second call
produces E0382. The generic FnOnce bound supplies no reusable-call or copy
guarantee. Return the result of one call instead.
Finally, replace run_three's todo!() with the three helper calls.
Pass the counter closure directly to tally, then read the counter after
that call returns. Its mutable borrow has ended by then. More generally,
such a borrow can end after the closure's last use; it need not last until
the end of the scope that contains the closure binding.
Your solution must compile, produce the required tuple and pass Clippy with warnings treated as errors.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.