We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership I: Moves, Copy, Clone, Drop step 12 of 20
drop(x) is just a function
Write drop yourself, then use it to schedule destruction.
fn my_drop<T>(_value: T) {}
pub fn schedule(names: Vec<String>, drop_after: Vec<usize>) -> Vec<String>
The least magical function in the standard library
Learners treat drop as compiler magic. Here is its actual definition, from
core::mem:
pub fn drop<T>(_x: T) {}
That is all of it. An empty body. There is no intrinsic, no compiler hook,
no special case in the type checker. It works for exactly one reason: _x is
taken by value, so calling drop(t) moves t into the function, and when
the function returns, its local parameter goes out of scope and Rust destroys it
like any other local.
Sit with that for a moment, because it retroactively explains every by-value
signature you have seen in this track. fn tag(l: String) -> String does not
merely “take a String” — it takes responsibility for destroying it unless it
passes that responsibility on. Ownership is not a rule layered on top of the
language; it is the mechanism, and drop is the smallest possible demonstration.
::: question Why is fn my_drop<T: Drop>(_value: T) {} wrong?
Because Drop is not “types that get destroyed” — it is “types with a
hand-written destructor”. String does not implement Drop. Neither does
i32, nor Vec<T>, nor almost anything you write. They are all still dropped;
they simply have no custom drop method, so their destruction is the compiler
recursively destroying their fields.
Adding T: Drop would make my_drop(String::new()) a compile error:
error[E0277]: the trait bound `String: Drop` is not satisfied
which is the opposite of what you want. std::mem::drop has no bound at all,
and that is deliberate — it must accept everything, because everything gets
dropped.
(There is a related joke in the standard library: drop on a Copy type does
nothing whatsoever, since the original is still there. rustc’s
dropping_copy_types lint warns you about it, and clippy’s drop_non_drop
warns when you explicitly drop a value with no destructor anywhere in it —
usually a sign you meant something else.)
:::
The other half: x.drop()
Drop::drop is a real method, so you would expect t.drop() to work. It is
specifically forbidden:
error[E0040]: explicit use of destructor method
|
| t.drop();
| ^^^^ explicit destructor calls not allowed
|
help: consider using `drop` function
|
| drop(t);
The starter contains that line, so you will meet the error rather than take my
word for it. The reason for the ban is a double-free: Drop::drop takes
&mut self, so calling it directly would run the destructor without
consuming the value, and the value would then be destroyed again at the end
of its scope. drop(t) cannot have that problem — it takes t by value, so
t is gone afterwards and the compiler knows it.
That is also why you can implement Drop::drop and never call it. You write
the destructor; the compiler decides when it runs.
What to build
schedule(names, drop_after)
Walk names in order, building a Tracked for each (the grader’s scaffolding
logs "new <name>" on construction and "drop <name>" in its destructor).
-
If the value’s index appears in
drop_after, hand it straight tomy_drop— it dies immediately, and the log shows that. - Otherwise keep it.
When the loop is done, release the survivors newest first, one at a time,
also through my_drop. Then return the log.
For names = ["a", "b", "c"] and drop_after = [1]:
new a, new b, drop b, new c, drop c, drop a
Indices in drop_after that are out of range select nothing. The scaffolding:
struct Tracked { name: String, log: Log } // NOT Clone
fn tracked-like constructor: Tracked::new(name: String, log: Log) -> Tracked
fn new_log() -> Log
fn snapshot(log: Log) -> Vec<String>
Tracked is deliberately not Clone, so there is no way to duplicate your way
around a move here.
A hint about the survivors
Vec::pop removes from the back, which is exactly “newest first”. Popping in a
while let Some(t) = kept.pop() loop and passing each t to my_drop gives
the required order and — worth noticing — is the same shape as the relay
problem near the start of the track.
Remember the grade is compile + tests + clippy -D warnings.
Loading visualization…
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.