We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership III: Lifetimes, Explicitly step 22 of 22
Generics, traits and lifetimes in one signature
Implement three functions that combine generic types with borrowed results. Keep the supplied signature checks and type alias unchanged.
pub fn best_by<T, K>(items: &[T], key: K) -> Option<&T>
where
K: Fn(&T) -> i64;
pub fn describe<T: Display>(items: &[String], tag: T) -> (String, Option<&str>);
pub fn store<'a, 'b: 'a, T>(long: &'b T, out: &mut Vec<&'a T>);
best_byreturns a reference to the element with the largest key. Keep the first element on ties, and returnNonefor an empty slice. Do not require elements to implementCopy,CloneorOrd.describereturns an owned summary formatted as<tag>#<count>and a borrowed string slice of the first item. Use the tag'sDisplayoutput and the number of strings, not their total length. Empty input produces<tag>#0andNone.storeappendslongtooutwithout changing existing entries. Add the missing outlives bound to the starter's signature; keep its body.
For example, the identity key on [3, 11, 7] selects 11. Describing
["alpha", "beta"] with tag "run" returns ("run#2", Some("alpha")).
An empty first string produces Some(""), not None.
Which reference does the result borrow?
In best_by, the output reference borrows from items. The elision rules
assign it the lifetime of that input slice, so no named lifetime is needed.
The same rule connects describe's returned &str to its items slice.
Its summary is a new owned String.
K and T can themselves contain references. That does not introduce extra
input reference lifetimes for this elision rule. In particular, describe
must not tie its returned slice to the lifetime of a borrowed tag.
Keep these two signatures elided. Naming their otherwise-elidable lifetimes
adds no information and triggers the needless_lifetimes Clippy check here.
Expressing an outlives relationship
In store, out holds references valid for 'a, while long is valid for
'b. The bound 'b: 'a means that 'b outlives 'a: it must last at
least as long. Equal lifetimes are allowed too.
This lets the function store the longer-lived shared reference where a shorter-lived one is expected. It does not extend the lifetime of the value or make the output vector borrowable for longer. The mutable borrow of the vector itself is separate from the lifetime of the references it stores.
Keep both named lifetimes for this exercise and add their relationship.
A different API could use one shared lifetime for long and the stored
references; the supplied two-lifetime signature makes the outlives bound
explicit. The compiler checks the body against that declared relationship,
rather than assuming that every caller happens to pass a long-lived value.
The parameter &'a T also implies T: 'a, so you do not need to add that
type-outlives bound. Lifetime parameters come before type parameters in the
declaration: <'a, 'b: 'a, T>.
Selecting the first maximum
The supplied keys return consistent results for the same element. The
exercise does not prescribe how many times you call a key. When comparing
a candidate with the current best, replace the best only for a strictly
larger key. Iterator::max_by_key keeps the last maximum, so using it
directly would violate the first-on-ties requirement.
Fn(&T) -> i64 allows the key to accept references with different borrow
lifetimes. It does not mean the closure must own all its data or be 'static;
a closure can also borrow values from its calling scope.
What the harness checks
KeyFn and the two constant function-pointer assignments check particular
instances of best_by and describe, including the input/output borrowing
relationship. These checks supplement the generic implementations; they
do not prove every part of the contract.
For the JSON report, the harness uses best_by twice: once with the value
itself as the key, then with -v.rem_euclid(10). The second selects the
smallest nonnegative remainder modulo 10, with the first value winning
ties. For negative numbers this is not the last digit of the absolute
value: -13 has remainder 7.
The report also includes the summary, first word, and values appended through
store. Empty selections become JSON null. Inputs may include any i64
value and arbitrary strings; preserve string contents exactly.
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.