英文:
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) -> R
is 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
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).
不,不是这样的。当声明 R
时,'b
不在上下文中,因此不能依赖它(这是一种看待方式,还有其他方式)。
This is necessary for APIs like
std::thread::LocalKey::with()
to be sound: ifR
was 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论