We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Closures and Iterators step 8 of 28
Trace a lazy map, filter and take pipeline
Build an iterator pipeline that logs each transformation and predicate call. Return the log in execution order.
pub fn trace(nums: Vec<i64>) -> Vec<String>
Use nums.iter(), followed by map, filter and take(3), in that order:
- The map closure logs
map:<x>using the original number, then yields x * 2. - The filter closure logs
filter:<y>using the doubled number, then keeps it if y % 4 == 0. - take(3) limits the output to the first three values that pass the filter.
Consume the pipeline, count its outputs, and append kept:<n> as the final
log entry. Return only the log, not the selected numbers. Format integers as
ordinary decimal text with no extra spaces.
Inputs are restricted to numbers whose doubles fit in i64. Zero and negative numbers are allowed; negative multiples of four pass the filter too.
Follow one input through both closures
For [1, 2, 4], the complete log is:
map:1
filter:2
map:2
filter:4
map:4
filter:8
kept:2
Mapping and filtering interleave. Each visited input is logged by map and then
by filter before processing the next input. Rejected values still generate
both entries. Empty input returns ["kept:0"].
Stop after three accepted values
For [2, 4, 6, 8, 10], the doubled values 4, 8 and 12 pass. The log ends with
filter:12 followed by kept:3. Inputs 8 and 10 are never mapped or tested.
The limit counts accepted values, not visited inputs. If fewer than three pass, the pipeline visits every input. Moving take before filter would change that behavior.
Repair all parts of the starter
The starter constructs an iterator but never consumes it, so its closures do not run. It also maps each input to (), because Vec::push returns (), and its filter accepts everything without logging. Finally, it never appends a kept entry.
Fix the map closure to log and then return the doubled number. Fix the filter to log and test that number. End the chain with count so it performs the work and gives you n. Append the final entry after the chain is consumed.
The unused-iterator diagnostic identifies the missing consumer. Assigning an
unused iterator to _ may silence a warning, but it does not consume it or
repair the result. Passing requires compilation, correct logs and Clippy with
warnings denied.
Laziness describes when work happens
Constructing this map/filter/take chain stores the source and closures without calling the mapping or filtering closures. A consumer then drives it. Calling next is one way to request items; consumers can also use specialized iterator methods internally. The exact sequence of internal method calls is not the point of the exercise. The observable log order and stopping position are.
These adapters do not create intermediate collections. The logging closures do allocate strings and grow a vector, so this instrumented pipeline is not an allocation-free computation or a performance benchmark.
Share the log with short borrows
Both closures remain part of the same chain. Capturing a separate &mut borrow of the same vector in each would produce conflicting borrows. The supplied RefCell<Vec<String>> lets both closures share the cell and borrow its contents mutably for each push.
Keep each borrow_mut guard within its logging statement. That releases map's guard before filter logs, avoiding a borrow conflict in this implementation. After consumption, use into_inner to recover the log and append kept.
The map closure receives &i64 from nums.iter(); |&x| copies the integer.
After mapping, the item is i64, but filter receives a reference to the item,
so |&y| copies the doubled value for its test.
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.