We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Async From First Principles step 2 of 25
Create, drop and run futures
Calling an async fn creates a future. Its body starts running when that
future is polled. Use this distinction to build a log in three passes.
pub fn laziness_log(tags: Vec<String>, drive: Vec<bool>) -> Vec<String>
The supplied record(tag, log) appends ran:<tag> when its body runs.
Keep record and the supplied block_on helper unchanged. Rewrite
laziness_log to do the following:
- For every tag in order, append
constructed:<tag>to the log, then create and store itsrecordfuture without running it. - For every
falseflag in order, appenddropped:<tag>, then drop that tag's stored future. - For every
trueflag in order, pass that tag's stored future toblock_on. Letrecordwrite the correspondingran:<tag>entry. - Return the log.
Finish each pass before starting the next. The two input vectors have equal lengths. Preserve tags exactly, including empty strings, duplicates and Unicode. Empty inputs return an empty log.
For tags = ["a", "b"] and drive = [true, false], return:
["constructed:a", "constructed:b", "dropped:b", "ran:a"]
Both futures were created before either was dropped or run. There is no
ran:b entry because that future was dropped without being polled.
What runs when?
Arguments are evaluated when you call an async function. In this exercise,
cloning a tag and the shared log handle happens immediately. The code
inside record waits until polling starts. Because record contains no
.await, its first poll appends the entry and completes the future.
The supplied block_on repeatedly polls, up to 100,000 times. It is enough
for this exercise, but it is not a general-purpose executor: it uses a
no-op waker and does not wait for wake notifications. Futures that depend
on timers or I/O need an appropriate runtime.
Repairing the starter
The starter uses .await directly inside a synchronous function, which
produces E0728. Use the supplied block_on to run the selected futures.
Replacing .await alone is not enough: the starter also interleaves the
log entries instead of completing three separate passes.
Every call to record returns the same future type, so you can store the
futures in a vector even though you cannot write out that type's name.
A Vec<Option<_>> gives each future a slot you can empty. Assigning None
drops the value in that slot. Calling take() moves the value out and
leaves None, so you can pass the selected future to block_on.
Dropping a future
Dropping an unpolled record future releases its captured values without
running its body. More generally, dropping a future does not undo effects
that have already happened or necessarily stop work it started elsewhere.
Cleanup can also run through destructors.
Use drop(fut) when you intend to consume and drop an owned future.
let _ = fut; does not move or drop an existing named future: _ is a
wildcard, not a new binding. let _fut = fut; moves it into a new binding
that is normally dropped at the end of its scope. Avoid relying on either
spelling to express immediate cancellation.
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.