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
Schedule destruction with a by-value helper
Repair the starter so it destroys each Tracked value at the required time. Use the supplied generic helper with an empty body:
fn my_drop<T>(_value: T) {}
pub fn schedule(names: Vec<String>, drop_after: Vec<usize>) -> Vec<String>
Required event order
Visit names in order. For each zero-based index, construct exactly one
Tracked value. Construction logs "new " followed by the unchanged name.
If that index appears in drop_after, pass the new value to my_drop immediately,
before constructing the next value. Otherwise, retain it. After all names
have been visited, pass the retained values to my_drop one at a time in
reverse creation order. Each destruction logs "drop " followed by its name.
Return the complete log after every value has been released.
For names ["a", "b", "c"] and drop_after [1], return:
["new a", "new b", "drop b", "new c", "drop c", "drop a"]
Duplicate indices select the same value once. Out-of-range indices select
nothing, and their order does not change the schedule. Indices are nonnegative
and fit usize. Empty names input produces an empty log. Names may be empty,
duplicated or contain arbitrary Unicode and control characters; preserve
them exactly. An empty name produces the strings "new " and "drop ",
including their trailing spaces. Equal names still represent distinct values.
Supplied helpers
The harness supplies these definitions; do not redefine them:
| Item | Purpose |
|---|---|
Log |
A shared handle to the event vector. |
new_log() -> Log |
Creates an empty log. |
Tracked::new(name: String, log: Log) -> Tracked |
Owns the name and logs construction. |
snapshot(log: Log) -> Vec<String> |
Copies the accumulated events. |
Tracked does not implement Clone. Cloning a Log handle shares the same log; it does not duplicate a Tracked value. Vec::pop removes the newest retained value, so a pop loop gives explicit control over the required release order. Do not rely on automatic Vec element destruction to provide that order.
Why an empty function can destroy a value
The standard library's drop function also takes its argument by value and has an empty body. Its parameter is dropped before the function returns. This uses the language's ordinary destruction rules. See the drop documentation.
Here is a complete example:
fn my_drop<T>(_value: T) {}
struct Notice(&'static str);
impl Drop for Notice {
fn drop(&mut self) {
println!("drop {}", self.0);
}
}
fn main() {
let notice = Notice("first");
my_drop(notice);
println!("after");
}
It prints drop first before after. Notice is moved into my_drop and
cannot be used afterward. For a Copy argument, the call instead receives
a copy, leaving the original usable. Passing a reference does not destroy
the referenced value.
Drop is not a requirement for cleanup
A Drop implementation supplies custom destructor code. A type without its
own Drop implementation can still own fields that need cleanup. String is
an example: it has no direct Drop implementation, but its owned storage is
released through its fields. Vec does implement Drop. Neither case calls
for a T: Drop bound on this generic helper.
Such a bound would reject String and i32, while accepting Tracked and Vec.
It is not a general test for whether a value needs destruction. Keep
fn my_drop<T>(_value: T) {}; T has the usual implicit Sized bound, and no
Drop bound is needed. Rustc's drop_bounds warning flags this misleading
use of the trait as a generic constraint.
Use my_drop(value), not value.drop()
The starter calls t.drop() directly, producing E0040. Explicit calls to
the Drop trait's destructor method are forbidden. That method borrows
&mut self; calling it as an ordinary method would leave the value usable
after cleanup and eligible for later cleanup again. Depending on the type,
that could cause resource misuse. Not every destructor frees memory.
Passing this non-Copy Tracked value to my_drop transfers ownership instead. Normal scope cleanup runs its destructor exactly once here. Replace the direct method call and preserve the explicit newest-first survivor loop.
Passing requires compilation, the exact event sequence and 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.