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) 更通用(接受更多生命周期),我们得到错误。

我尝试了其他生命周期组合,但只有这个组合会出现此类错误。但我不能说这是否真的发生了。