We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Closures and Iterators step 17 of 28
from_fn and successors: iterators without writing a struct
Build two sequences using from_fn and successors, then concatenate them.
pub fn drive(script: Vec<u32>) -> Vec<u32>
Part A: follow the jumps
Start at index zero. If the index is in bounds, yield its value v, then
advance by v + 1 positions. Stop once the index is outside the input.
A zero value advances one position; it does not end the walk.
For [2, 9, 9, 3, 9, 9, 9, 1, 5], visit indices 0, 3 and 7, yielding
[2, 3, 1]. The next index is 9, outside the vector.
Part B: generate successors
Use the last value from part A as the seed, or 1 if part A was empty.
Always emit that seed. If the current value is less than 1000, emit
current * 2 + 1 next. Otherwise stop.
The first value reaching or exceeding 1000 is included. A seed already at or above 1000 produces only itself. The seed is not removed from part A, so it appears again when part B begins.
| Script | Combined result |
|---|---|
[] |
[1, 3, 7, 15, 31, 63, 127, 255, 511, 1023] |
[0] |
[0, 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023] |
[999] |
[999, 999, 1999] |
[1000] |
[1000, 1000] |
[u32::MAX] |
[u32::MAX, u32::MAX] |
Inputs may contain any u32 value. The input and output fit in memory.
Implement the walk with from_fn and the recurrence with successors.
Return an Option from the walk
from_fn calls an FnMut() -> Option<T> closure on each next() call.
The starter returns a bare u32, causing E0308. Return Some(v) for a
visited value and None when the index is out of bounds.
let v = *script.get(i)?; handles that lookup: get returns an Option,
and ? returns None from the closure if there is no element. Advance the
index without wrapping back into the input; saturating addition is useful
because any jump past the last element must end the walk anyway.
from_fn does not itself promise permanent exhaustion. A later next()
calls the closure again, even after it returned None. This walk stays
exhausted because its index remains outside the vector. Use .fuse() when
you need that guarantee for a closure that might later return Some.
Compute a successor only when needed
successors(Some(seed), ...) stores the first value and passes a reference
to the current value into its closure to compute the next one. Return
Some(next) below the threshold and None at or above it. Once exhausted,
this iterator stays exhausted.
Use an explicit conditional for this recurrence:
fn next_value(x: u32) -> Option<u32> {
if x < 1000 {
Some(x * 2 + 1)
} else {
None
}
}
bool::then_some(value) evaluates its argument even when the condition is
false. Thus (x < 1000).then_some(x * 2 + 1) can overflow on a large seed
that should immediately stop. then(|| value) is lazy; the explicit if
above also makes the arithmetic guard clear.
The walk advances at least one position per yielded value. The recurrence
increases only while its input is below 1000, so computed successors are
at most 1999. Those bounds explain termination and keep the multiplication
safe; x * 2 + 1 is not safe for every possible u32.
Your solution must compile, use both iterator constructors, match the output 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.