为什么在使用 sort_by_key 对向量进行排序时不能使用返回引用的键函数?
我正在尝试使用返回对向量中字符串的引用的键函数对 Vec
进行排序。一个人为的示例是使用恒等函数作为关键函数(这当然是无用的,但它是重现我的问题的最小示例):
fn key(x: &String) -> &String {
x
}
fn example(items: Vec<String>) {
items.sort_by_key(key);
}
这给出了以下错误:
error[E0308]: mismatched types
--> src/lib.rs:6:11
|
6 | items.sort_by_key(key);
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected associated type `<for<'r> fn(&'r String) -> &'r String {key} as FnOnce<(&String,)>>::Output`
found associated type `<for<'r> fn(&'r String) -> &'r String {key} as FnOnce<(&String,)>>::Output`
= note: the required lifetime does not necessarily outlive the empty lifetime
note: the lifetime requirement is introduced here
我不明白为什么会出现此错误,所以我尝试了来追踪这一点。我首先实现了我自己的 sort_by_key()
版本:
fn sort_by_key<T, K: Ord>(a: &mut [T], key: fn(&T) -> K) {
a.sort_by(|x, y| key(x).cmp(&key(y)));
}
当尝试调用此函数时,我得到了看起来像“相反”的错误:
error[E0308]: mismatched types
--> src/lib.rs:6:29
|
6 | sort_by_key(&mut items, key);
| ^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r> fn(&'r String) -> &String`
found fn pointer `for<'r> fn(&'r String) -> &'r String`
我可以通过将键类型固定为 &T
而不是使用泛型参数 K
,或者使用 &K
而不是 K
作为返回类型关键功能:
fn sort_by_key_v2<T: Ord>(a: &mut [T], key: fn(&T) -> &T) {
a.sort_by(|x, y| key(x).cmp(&key(y)));
}
fn sort_by_key_v3<T, K: Ord>(a: &mut [T], key: fn(&T) -> &K) {
a.sort_by(|x, y| key(x).cmp(&key(y)));
}
我也尝试添加生命周期注释,但是只是转移了错误而没有解决它。
为什么我会收到这些错误?有什么方法可以修复它们,同时保持密钥类型 K 完全通用吗?
I'm trying to sort a Vec<String>
using a key function that returns references to the strings in the vector. A contrived example is to use the identity function as key function (which of course is useless, but it's the minimal example to reproduce my problem):
fn key(x: &String) -> &String {
x
}
fn example(items: Vec<String>) {
items.sort_by_key(key);
}
This gives the following error:
error[E0308]: mismatched types
--> src/lib.rs:6:11
|
6 | items.sort_by_key(key);
| ^^^^^^^^^^^ lifetime mismatch
|
= note: expected associated type `<for<'r> fn(&'r String) -> &'r String {key} as FnOnce<(&String,)>>::Output`
found associated type `<for<'r> fn(&'r String) -> &'r String {key} as FnOnce<(&String,)>>::Output`
= note: the required lifetime does not necessarily outlive the empty lifetime
note: the lifetime requirement is introduced here
I don't understand why I get this error, so I tried to track this down. I first implemented my own version of sort_by_key()
:
fn sort_by_key<T, K: Ord>(a: &mut [T], key: fn(&T) -> K) {
a.sort_by(|x, y| key(x).cmp(&key(y)));
}
When trying to call this function, I get what looks like the "opposite" error:
error[E0308]: mismatched types
--> src/lib.rs:6:29
|
6 | sort_by_key(&mut items, key);
| ^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r> fn(&'r String) -> &String`
found fn pointer `for<'r> fn(&'r String) -> &'r String`
I can make this code compile by fixing the key type to &T
instead of using the generic parameter K
, or by using &K
instead of K
as return type for the key function:
fn sort_by_key_v2<T: Ord>(a: &mut [T], key: fn(&T) -> &T) {
a.sort_by(|x, y| key(x).cmp(&key(y)));
}
fn sort_by_key_v3<T, K: Ord>(a: &mut [T], key: fn(&T) -> &K) {
a.sort_by(|x, y| key(x).cmp(&key(y)));
}
I also tried adding lifetime annotations, but that only shifted the error around without resolving it.
Here's the three versions of the sort_by_key()
function on the Playground.
Why am I getting these errors? Is there any way to fix them while keeping the key type K
completely generic?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
现在,您必须使用“长”形式:
原因和修复是一回事:Rust 目前的表现力不足以代表您想要的东西。所需的功能称为通用关联类型(GAT);以前称为关联类型构造函数 (ATC) 或更高种类的类型 (HKT)。
来自相关问题:
我不知道
sort_by_key
的签名在实施后是否能够无缝转移到 GAT。在这一点上似乎值得怀疑,因为 Fn* 特征本身可能需要更改。在控制所有类型签名的类似情况下,您可以要求返回引用:
这是不理想的,因为现在您无法返回非引用,但在实现 GAT 之前根本没有完整的解决方案。您也许可以添加并行方法,例如
sort_by
和sort_by_key
,具体取决于您的情况。For now, you have to use the "long" form:
The cause and fix are one-and-the same: Rust is simply not currently expressive enough to represent what you want. The feature needed is called generic associated types (GATs); previously known as associated type constructors (ATCs) or higher-kinded types (HKTs).
From the associated issue:
I don't know if the signature for
sort_by_key
will be able to be seamlessly moved to a GAT when they are implemented. It seems doubtful at this point, as theFn*
traits themselves would likely need to be changed.In similar cases where you control the signature of all the types, you can require that a reference be returned:
This is non-ideal because now you cannot return a non-reference, but there's simply no complete solution until GATs are implemented. You may be able to add a parallel methods like
sort_by
andsort_by_key
, depending on your case.正如 @Shepmaster 解释的,您不能使用
sort_by_key
函数来处理返回类型的通用关联生命周期key
函数,但这里是始终返回引用的键函数的变体:您还可以写下键函数的生命周期要求:
请参阅操场上的示例。
As @Shepmaster explained you cannot have a
sort_by_key
function handling generic associated lifetimes for the return type of thekey
function, but here is a variant for a key function always returning a reference:You could also write down the lifetime requirements for the key function:
See example on playground.
基于 Shepmaster 答案的最简洁的解决方法(IMO)是:
只需将
slice.sort_by_key(key)
转换为slice.sort_by(ref_key(key))
即可使用它。代码>.The cleanest workaround (IMO) for this that builds on Shepmaster's answer is:
It can be used simply by converting
slice.sort_by_key(key)
toslice.sort_by(ref_key(key))
.