Like the other topic said, you can use sort_by
(or sort_by_unstable
) instead.
The rest of this post looks at your intuition and the various ways it might work, but doesn't today. The TL;DR is that there is no such K + '_
feature for type parameters K
.
Type parameters always resolve to a single type. K + '_
doesn't mean anything for type parameter K
, but if it did, it would probably mean K: '_
and not actually help; in the given context that would be the same restrictions that are on K
today, because K
must still be a single type outside of that bound. You instead need some way to declare the output (K
) in a location where it can "see" the input lifetime it relies on.
So the K + '_
you intuited would instead have to be something like a GAT (generic associated type), and not a type parameter:
// Not how these traits actually work
F: FnMut(&T) -> F::Output<'_>
But that's not how FnMut
and friends are designed -- and GATs are not stable. The closest we have right now is return position impl Trait
, but that can't be used in bounds.
// Not supported, but perhaps closest to what you intuited
// (You also lose the ability to "name" `K`, in current Rust)
F: FnMut(&T) -> impl Ord + '_
Alternatively, one would think it was possible with the unboxed_closures
feature and higher-ranked bounds, but even that hits normalization issues.
#![feature(unboxed_closures)]
// ...
pub fn sort_by_key<F>(&mut self, f: F)
where
// The same bound but without naming the output type
F: for<'any> FnMut<(&'any T,)>,
// Saying the output type must always be `Ord`
for<'any> <F as FnOnce<(&'any T,)>>::Output: Ord,
(See also or more specifically probably this one.)
Any of these that did work would be an increased commitment on behalf of the method, i.e. would support cases that aren't supported today. However, assuming they didn't break inference, it's probably a reasonable extension.
Alternatively you would need "type constructor parameters" instead of type parameters:
// Made up future Rust syntax and capability
pub fn sort_by_key<K<*>, F>(&mut self, F)
where
F: FnMut(&T) -> K<'_>,
for<'any> K<'any>: Ord,
But this version is actually less capable than the above future possibilities, as by stating the Ord
bound separately from F
and T
, K<'_>
must be defined for all lifetimes. In the above examples, it would only need to be defined where T
is defined. (If T
is static, this makes no difference, but T
might not be static.)
Contrast with F: FnMut(&T) -> impl Ord + '_
, where the Ord
bound on the output is within the context of the input (&T
).
Moreover, I'm unaware of any serious proposal to add type constructor parameters to Rust.