使用线程时终生难过

时间:2015-01-03 12:30:41

标签: closures rust lifetime

我很难将其编译成:

use std::thread::{self, JoinHandle};

struct Foo<'c> {
    foo: &'c str,
}

impl<'c> Foo<'c> {
    fn use_in_another_thread<F>(self, mut cb: F) -> JoinHandle<Foo<'c>>
        where F: FnOnce(&mut Foo),
              F: Send
    {
        thread::spawn(move || {
            cb(&mut self);
            self
        })
    }
}

fn main() {}

据我所知,生命时间是合理的,但我收到错误......

error[E0477]: the type `[closure@src/main.rs:12:23: 15:10 cb:F, self:Foo<'c>]` does not fulfill the required lifetime
  --> src/main.rs:12:9
   |
12 |         thread::spawn(move || {
   |         ^^^^^^^^^^^^^
   |
   = note: type must outlive the static lifetime

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:14:13
   |
14 |             self
   |             ^^^^
   |
note: first, the lifetime cannot outlive the lifetime 'c as defined on the body at 11:4...
  --> src/main.rs:11:5
   |
11 |       {
   |  _____^ starting here...
12 | |         thread::spawn(move || {
13 | |             cb(&mut self);
14 | |             self
15 | |         })
16 | |     }
   | |_____^ ...ending here
note: ...so that expression is assignable (expected std::thread::JoinHandle<Foo<'c>>, found std::thread::JoinHandle<Foo<'_>>)
  --> src/main.rs:12:9
   |
12 |           thread::spawn(move || {
   |  _________^ starting here...
13 | |             cb(&mut self);
14 | |             self
15 | |         })
   | |__________^ ...ending here
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `Foo<'_>` will meet its required lifetime bounds
  --> src/main.rs:12:9
   |
12 |         thread::spawn(move || {
   |         ^^^^^^^^^^^^^

我不明白错误所指的生命周期 - 封闭体的生命周期? - 或者为什么他们必须比静态寿命更长。

1 个答案:

答案 0 :(得分:8)

导致此问题的生命周期约束是Thread::spawn中的生命周期约束,它要求FnOnce闭包为SendSend需要'static,这意味着数据不包含非'static数据。您的数据Foo包含借用的str,而不是'static,这使得Foo'static。因此,您无法跨线程发送Foo

这是为什么?由于Foo包含借用,因此它仅在很短的时间内有效。如果Rust允许您将Foo的实例发送到另一个线程,那么该线程在借用的数据变为无效之后很久就可以轻松使用Foo

您可能认为这实际上过于严格,而且您是对的。只要你能向借用检查器证明线程在某个生命周期内终止,就没有理由不允许本地并行。 Rust目前没有构造可以做到这一点,但是这个问题有一些未来的解决方案,例如this RFC扩展Send特征以允许本地并行。