在闭包内部使用引用时存在冲突的生命周期要求

Conflicting lifetime requirements when using a reference inside of a closure

您好,在闭包内部使用引用时,我遇到了生命周期要求冲突的问题。这是一个最小的复制:

fn main() {
    let mut v: Vec<&i32> = Vec::new();
    let x = 10;
    run(move || v.push(&x));
}

fn run<F: 'static + FnMut()>(mut f: F) {
    f();
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=22a340b1d213ba5cc2222d5469159f8e

run 的定义来自第三方库,因此我无法更改其签名(请参阅 winit::EventLoop::run)。这是错误:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
 --> src/main.rs:4:24
  |
4 |     run(move || v.push(&x));
  |                        ^^
  |
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 4:9...
 --> src/main.rs:4:9
  |
4 |     run(move || v.push(&x));
  |         ^^^^^^^^^^^^^^^^^^
note: ...so that closure can access `x`
 --> src/main.rs:4:24
  |
4 |     run(move || v.push(&x));
  |                        ^^
  = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:4:9: 4:27]` will meet its required lifetime bounds
 --> src/main.rs:4:5
  |
4 |     run(move || v.push(&x));
  |     ^^^

error: aborting due to previous error

我无法理解为什么访问 x 会出现问题。看起来这段代码应该是可行的,因为 x 在闭包的整个生命周期中都保留在堆栈中。有什么方法可以让我从闭包中引用堆栈上的变量,给定 run?

的签名

绑定在run()上的F: 'static意味着它需要一个拥有它引用的数据或引用静态生命周期数据的未来。特别是,编译器无法证明变量 x 会一直存在到程序结束 - 尽管对于这个特定程序来说可能确实如此,因为 x 恰好定义在顶部附近main().

您无法更改 run() 的签名,但如果您可以控制闭包及其使用向量的方式,则可以通过切换到引用计数智能指针的向量来使其工作而不是引用向量:

fn main() {
    let mut v: Vec<Arc<i32>> = vec![];
    let x = Arc::new(10);
    run(move || v.push(x.clone()));
}

请注意,对 clone() 的调用实际上并未克隆 x,它只是“克隆”Arc,即增加引用计数。 v 的元素大小没有改变(仍然是每个指针的大小),但现在每个元素将在堆上单独分配。