The core of the issue is that drop
is not a single function, but rather a parameterized set of functions that each drop some particular type.
(问题的核心在于drop
不是单个函数,而是一组参数化的函数,每个函数都删除某些特定类型。)
To satisfy a higher-ranked trait bound (hereafter hrtb), you'd need a single function that can simultaneously take references to a type with any given lifetime. (为了满足势必更高的排名性状(以下简称hrtb),你需要一个单一的功能,可以同时进行的引用与任何给定的寿命类型。)
We'll use drop
as our typical example of a generic function, but all this applies more generally too.
(我们将使用drop
作为泛型函数的典型示例,但这也更普遍地适用。)
Here's the code for reference: fn drop<T>(_: T) {}
. (以下是供参考的代码: fn drop<T>(_: T) {}
。)
Conceptually, drop
is not a single function, but rather one function for every possible type T
.
(从概念上讲, drop
不是单个函数,而是每个可能类型T
一个函数。)
Any particular instance of drop
takes only arguments of a single type. (drop
任何特定实例仅采用单一类型的参数。)
This is called monomorphization . (这称为单态化 。)
If a different T
is used with drop
, a different version of drop
is compiled. (如果不同的T
与用于drop
,不同版本的drop
被编译。)
That's why you can't pass a generic function as an argument and use that function in full generality (see this question ) (这就是为什么您不能将通用函数作为参数传递而不能完全泛泛地使用该函数的原因(请参阅此问题 ))
On the other hand, a function like fn pass(x: &i32) -> &i32 {x}
satisfies the hrtb for<'a> Fn(&'a i32) -> &'a i32
.
(另一方面, fn pass(x: &i32) -> &i32 {x}
之类的函数for<'a> Fn(&'a i32) -> &'a i32
。)
Unlike drop
, we have a single function that simultaneously satisfies Fn(&'a i32) -> &'a i32
for every lifetime 'a
. (不像drop
,我们有一个单一的功能,可以同时满足Fn(&'a i32) -> &'a i32
每寿命'a
。)
This is reflected in how pass
can be used. (这反映在如何使用pass
上。)
fn pass(x: &i32) -> &i32 {
x
}
fn two_uses<F>(f: F)
where
for<'a> F: Fn(&'a i32) -> &'a i32, // By the way, this can simply be written
// F: Fn(&i32) -> &i32 due to lifetime elision rules.
// That applies to your original example too.
{
{
// x has some lifetime 'a
let x = &22;
println!("{}", f(x));
// 'a ends around here
}
{
// y has some lifetime 'b
let y = &23;
println!("{}", f(y));
// 'b ends around here
}
// 'a and 'b are unrelated since they have no overlap
}
fn main() {
two_uses(pass);
}
(playground)
((操场))
In the example, the lifetimes 'a
and 'b
have no relation to each other: neither completely encompasses the other.
(在该示例中,生命周期'a
和'b
彼此之间没有关系:两者都不完全包含彼此。)
So there isn't some kind of subtyping thing going on here. (因此,这里没有发生任何子类型化的事情。)
A single instance of pass
is really being used with two different, unrelated lifetimes. (实际上, pass
的单个实例实际上具有两个不同的,不相关的生存期。)
This is why drop
doesn't satisfy for<'a> FnOnce(&'a T)
.
(这就是为什么drop
for<'a> FnOnce(&'a T)
不满足for<'a> FnOnce(&'a T)
。)
Any particular instance of drop
can only cover one lifetime (ignoring subtyping). (drop
任何特定实例只能覆盖一个生命周期(忽略子类型)。)
If we passed drop
into two_uses
from the example above (with slight signature changes and assuming the compiler let us), it would have to choose some particular lifetime 'a
and the instance of drop
in the scope of two_uses
would be Fn(&'a i32)
for some concrete lifetime 'a
. (如果我们从上面的示例two_uses
drop
传递给two_uses
(稍作签名更改,并假设编译器允许我们这样做),则必须选择一些特定的生存期'a
并且two_uses
范围内drop
的实例为Fn(&'a i32)
保持一定的具体寿命'a
。)
Since the function would only apply to single lifetime 'a
, it wouldn't be possible to use it with two unrelated lifetimes. (由于该函数仅适用于单个生命周期'a
,因此无法将其与两个不相关的生命周期一起使用。)
So why does the toilet closure get a hrtb?
(那么,为什么马桶盖得到HRTB?)
When inferring the type for a closure, if the expected type hints that a higher-ranked trait bound is needed, the compiler will try to make one fit . (在推断闭包的类型时,如果期望的类型暗示需要更高等级的特征绑定, 则编译器将尝试使其适合 。)
In this case, it succeeds. (在这种情况下,它成功。)
Issue #41078 is closely related to this and in particular, eddyb's comment here gives essentially the explanation above (though in the context of closures, rather than ordinary functions).
(问题#41078与此密切相关,尤其是eddyb的注释在本质上给出了上面的解释(尽管在闭包的上下文中,而不是在普通函数中)。)
The issue itself doesn't address the present problem though. (问题本身并未解决当前的问题。)
It instead addresses what happens if you assign the toilet closure to a variable before using it (try it out!). (相反,它解决了如果在使用前将马桶盖分配给变量(尝试一下!)会发生什么情况。)
It's possible that the situation will change in the future, but it would require a pretty big change in how generic functions are monomorphized.
(情况将来可能会改变,但是这将需要对泛型函数的单一化方式进行很大的改变。)