We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Performance and Data Layout step 10 of 20
Filter records without cloning their tags
Remove unnecessary tag copies from a record-filtering function:
pub struct Record {
pub id: u32,
pub name: String,
pub tags: Vec<String>,
}
pub fn summarise<'a>(records: &'a [Record], tag: &str) -> Vec<(u32, &'a str)>
Return each matching record's ID and a borrowed view of its name. A record
matches when at least one tag equals tag exactly. Return it once even if
the same tag appears several times. Sort results by ascending ID; IDs in
the exercise inputs are unique. Leave the records unchanged.
Empty input or no matches produces an empty vector. Empty names and empty tags are valid strings and use the same matching rules. Comparisons are case-sensitive; do not trim or normalize tags.
For example, records with IDs 8, 2 and 5, where only IDs 8 and 2 have the requested tag, produce the names for IDs 2 and 8 in that order.
The starter already returns the right values. Its problem is that it clones each record's tag vector before checking for a match. Compare borrowed tags instead, keeping the public signature and sorted output.
Tie the returned names to the records
The output contains &'a str, so its names borrow from records for the
lifetime described by 'a. The tag argument has an independent lifetime:
a query string does not need to stay alive while the returned names are used.
With two borrowed inputs and no receiver, omitting this output lifetime relationship leaves Rust unable to infer which input supplies the names. The compiler reports E0106.
record.name.as_str() supplies a borrowed name. This avoids allocating a
new string for each result. The return type does not prohibit all internal
cloning, as the starter itself demonstrates; it specifies where the output
references come from.
What the allocation check measures
The harness counts allocator calls during summarise, including allocation,
zeroed allocation and reallocation calls. Record construction and output
serialization happen outside that measured interval. Each run must stay
within 64 counted calls, including a case with 50,000 records.
The result vector needs storage and may grow several times. That growth is allowed within the budget; the task does not require mathematically constant allocation count for arbitrarily large inputs. Borrowing for the filter avoids per-record temporary tag collections.
Cloning a Vec<String> duplicates its elements. For nonempty owned strings,
that includes copying their text into owned storage, not merely copying a
three-word header. Empty values and allocation strategies affect exact
counts, so do not assume one universal allocation cost for every clone.
sort_unstable_by_key sorts the result in place without allocating. With
unique IDs, equal-key stability does not affect the required ordering.
The returned ID numbers and string references are copied into the result;
the underlying name text is borrowed.
Decide whether a copy serves the API
Here the function only reads tags, and the caller keeps the records alive. Borrowing is enough. Other APIs may need an independent owned snapshot or a value that outlives its source, in which case cloning can be appropriate.
Arc::clone shares ownership of one allocation; it does not create an
independent copy of the contents. Shared mutation then needs a suitable
access protocol. Choosing Arc, Rc, a lock or an owned clone depends on
the required behavior, not a blanket rule that clones are bad.
Clippy can identify some unnecessary conversions and clones, but its silence does not establish good allocation behavior. Some lints are opt-in, and no single lint proves that a clone is needed or inexpensive.
Use the allocation check to verify this task. For a real performance claim, benchmark a representative workload and report the code, input and build settings. Removing this clone avoids unnecessary work, but no universal speedup follows from that fact alone.
Submissions must compile, pass the cases and pass the Rust Clippy gate.
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.