英文:
Rust HRTB is identical but compiler says one type is more general than the other
问题
以下是翻译好的部分:
编译器在编译此代码时报告了一个错误:
error[E0308]: mismatched types
--> src/main.rs:14:5
|
14 | enter(x, identity);
| ^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'b> FnOnce(&'b i32,)`
found trait `for<'a> FnOnce(&'a i32,)`
note: the lifetime requirement is introduced here
--> src/main.rs:3:35
|
3 | F: for<'b> FnOnce(&'b i32) -> R,
| ^
我理解的是,trait 约束 for<'b> FnOnce(&'b i32) -> R 比 identity 的签名 for<'a> fn(&'a i32) -> &'a i32 更一般,所以它应该通过。
然而,通用的 -> R 似乎是阻止编译的罪魁祸首,但我不知道为什么。
英文:
The following code is fully type annotated:
fn enter<'a, F, R>(x: &'a i32, func: F) -> R
where
F: for<'b> FnOnce(&'b i32) -> R,
{
func(x)
}
fn identity<'a>(x: &'a i32) -> &'a i32 {
x
}
fn main() {
let x = &42;
enter(x, identity);
}
The compiler reports an error when compiling it:
error[E0308]: mismatched types
--> src/main.rs:14:5
|
14 | enter(x, identity);
| ^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected trait `for<'b> FnOnce<(&'b i32,)>`
found trait `for<'a> FnOnce<(&'a i32,)>`
note: the lifetime requirement is introduced here
--> src/main.rs:3:35
|
3 | F: for<'b> FnOnce(&'b i32) -> R,
| ^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error
My understanding is that the trait bound for<'b> FnOnce(&'b i32) -> R is more general than identity's signature for<'a> fn(&'a i32) -> &'a i32, so it should pass.
However, the generic -> R seems to be the culprit that stops the compilation but I don't know why.
I noticed there are similar questions, but they experienced the error because their types were not fully annotated and the compiler incorrectly inferred the type.
Related:
答案1
得分: 3
My understanding is that the trait bound
for<'b> FnOnce(&'b i32) -> Ris more general thanidentity's signaturefor<'a> fn(&'a i32) -> &'a i32, so it should pass.
我的理解是,特质约束 for<'b> FnOnce(&'b i32) -> R 比 identity 的签名 for<'a> fn(&'a i32) -> &'a i32 更通用,所以它应该通过。
No it is not. When
Ris declared,'bis not in the context, so it cannot depend on it (this is one way to view that, there are others).
不,不是这样的。当声明 R 时,'b 不在上下文中,因此不能依赖它(这是一种看待方式,还有其他方式)。
This is necessary for APIs like
std::thread::LocalKey::with()to be sound: ifRwas allowed to contain the lifetime (implicit in the case ofwith()), references to the thread local could escape the closure andwith(), and then used on different threads, causing UB.
这对于像 std::thread::LocalKey::with() 这样的 API 来说是 必要的,如果允许 R 包含生命周期(在 with() 的情况下是隐式的),对线程本地的引用可能会逃逸闭包和 with(),然后在不同的线程上使用,导致未定义行为(UB)。
As far as I know, there is no way to have a generic return type and allow it to reference the parameters.
据我所知,目前没有办法使泛型返回类型并允许它引用参数。
英文:
> My understanding is that the trait bound for<'b> FnOnce(&'b i32) -> R is more general than identity's signature for<'a> fn(&'a i32) -> &'a i32, so it should pass.
No it is not. When R is declared, 'b is not in the context, so it cannot depend on it (this is one way to view that, there are others).
This is necessary for APIs like std::thread::LocalKey::with() to be sound: if R was allowed to contain the lifetime (implicit in the case of with()), references to the thread local could escape the closure and with(), and then used on different threads, causing UB.
As far as I know, there is no way to have a generic return type and allow it to reference the parameters.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论