Rust:为什么将闭包绑定到变量会改变类型?
Rust: Why does the binding of the closure to a variable change the type?
我有这段(最简化的)代码:
fn returns_closure() -> Box<dyn Fn(&u64)> {
let closure = |_| ();
Box::new(closure)
}
这不会编译并出现一条无用的错误消息:
error[E0308]: mismatched types
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&u64,)>`
但是,当我不先将闭包绑定到变量上,而是直接在 Box 的构造函数中创建它时,它会编译:
fn returns_closure() -> Box<dyn Fn(&u64)> {
Box::new(|_| ())
}
为什么第一个编译不通过,两者有什么区别?
编辑:
Emouns 的回答似乎是正确的。
我用夜间工具链 (1.52.0) 编译了完全相同的代码,得到了一个更好的错误:
error: implementation of `FnOnce` is not general enough
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 u64)` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2`
正如@frankenapps 指出的那样,如果您使用 let closure = |_: &u64|();
那么您就不会收到此错误。那么这是怎么回事?
为了弄清楚这一点,我进行了以下使用显式生命周期的编辑(而不是让编译器为我们删除它们)以努力获得相同的错误消息:
fn returns_closure<'a>() -> Box<dyn Fn(&'_ u64)> {
let closure = |_: &'a u64| ();
Box::new(closure)
}
运行 此代码向我们提供以下错误消息:
rror[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `for<'r> Fn<(&'r u64,)>`
found type `Fn<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
错误消息不完全相同,因为我们使用的是显式生命周期,但错误类型仍然是 one type is more general than the other
。
所以我们在这里看到的可能是生命周期省略的错误。
你可以看到我给闭包赋予了与函数相同的生命周期 ('a
),但是函数 returns dyn Fn(&'_ u64)
。这里请注意 '_
,它是任何生命周期的替身,而不仅仅是 'a
。
因此,return 类型 &'_ u64
比闭包 (&'a u64
) 更通用(接受更多生命周期),我们得到错误。
我尝试了其他生命周期组合,但只有这个组合会出现此类错误。但我不能说这是否真的发生了。
我有这段(最简化的)代码:
fn returns_closure() -> Box<dyn Fn(&u64)> {
let closure = |_| ();
Box::new(closure)
}
这不会编译并出现一条无用的错误消息:
error[E0308]: mismatched types
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&u64,)>`
但是,当我不先将闭包绑定到变量上,而是直接在 Box 的构造函数中创建它时,它会编译:
fn returns_closure() -> Box<dyn Fn(&u64)> {
Box::new(|_| ())
}
为什么第一个编译不通过,两者有什么区别?
编辑: Emouns 的回答似乎是正确的。 我用夜间工具链 (1.52.0) 编译了完全相同的代码,得到了一个更好的错误:
error: implementation of `FnOnce` is not general enough
--> src/main.rs:3:5
|
3 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 u64)` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2`
正如@frankenapps 指出的那样,如果您使用 let closure = |_: &u64|();
那么您就不会收到此错误。那么这是怎么回事?
为了弄清楚这一点,我进行了以下使用显式生命周期的编辑(而不是让编译器为我们删除它们)以努力获得相同的错误消息:
fn returns_closure<'a>() -> Box<dyn Fn(&'_ u64)> {
let closure = |_: &'a u64| ();
Box::new(closure)
}
运行 此代码向我们提供以下错误消息:
rror[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `for<'r> Fn<(&'r u64,)>`
found type `Fn<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/lib.rs:4:5
|
4 | Box::new(closure)
| ^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `FnOnce<(&u64,)>`
found type `FnOnce<(&'a u64,)>`
note: this closure does not fulfill the lifetime requirements
--> src/lib.rs:3:19
|
3 | let closure = |_: &'a u64| ();
| ^^^^^^^^^^^^^^^
错误消息不完全相同,因为我们使用的是显式生命周期,但错误类型仍然是 one type is more general than the other
。
所以我们在这里看到的可能是生命周期省略的错误。
你可以看到我给闭包赋予了与函数相同的生命周期 ('a
),但是函数 returns dyn Fn(&'_ u64)
。这里请注意 '_
,它是任何生命周期的替身,而不仅仅是 'a
。
因此,return 类型 &'_ u64
比闭包 (&'a u64
) 更通用(接受更多生命周期),我们得到错误。
我尝试了其他生命周期组合,但只有这个组合会出现此类错误。但我不能说这是否真的发生了。