【问题标题】:Parameter type may not live long enough (with threads)参数类型的寿命可能不够长(使用线程)
【发布时间】:2015-08-18 22:41:40
【问题描述】:

这类似于Parameter type may not live long enough?,但我对解决方案的解释似乎不起作用。我最初的归结测试用例是:

use std::fmt::Debug;
use std::thread;

trait HasFeet: Debug + Send + Sync + Clone {}

#[derive(Debug, Clone)]
struct Person;

impl HasFeet for Person {}

#[derive(Debug, Copy, Clone)]
struct Cordwainer<A: HasFeet> {
    shoes_for: A,
}

impl<A: HasFeet> Cordwainer<A> {
    fn make_shoes(&self) {
        let cloned = self.shoes_for.clone();
        thread::spawn(move || {
            println!("making shoes for = {:?}", cloned);
        });
    }
}

这给了我错误:

error[E0310]: the parameter type `A` may not live long enough
  --> src/main.rs:19:9
   |
16 | impl<A: HasFeet> Cordwainer<A> {
   |      -- help: consider adding an explicit lifetime bound `A: 'static`...
...
19 |         thread::spawn(move || {
   |         ^^^^^^^^^^^^^
   |
note: ...so that the type `[closure@src/main.rs:19:23: 21:10 cloned:A]` will meet its required lifetime bounds
  --> src/main.rs:19:9
   |
19 |         thread::spawn(move || {
   |         ^^^^^^^^^^^^^

我没有创建A 'static,而是为HasFeet trait 添加了一个明确的生命周期:

use std::fmt::Debug;
use std::thread;

trait HasFeet<'a>: 'a + Send + Sync + Debug {}

#[derive(Debug, Copy, Clone)]
struct Person;

impl<'a> HasFeet<'a> for Person {}

struct Cordwainer<'a, A: HasFeet<'a>> {
    shoes_for: A,
}

impl<'a, A: HasFeet<'a>> Cordwainer<'a, A> {
    fn make_shoes(&self) {
        let cloned = self.shoes_for.clone();
        thread::spawn(move || {
            println!("making shoes for = {:?}", cloned);
        })
    }
}

这现在给了我错误:

error[E0392]: parameter `'a` is never used
  --> src/main.rs:11:19
   |
11 | struct Cordwainer<'a, A: HasFeet<'a>> {
   |                   ^^ unused type parameter
   |
   = help: consider removing `'a` or using a marker such as `std::marker::PhantomData`

我认为 'a 被用作 HasFeet 特征的生命周期参数。我在这里做错了什么?

【问题讨论】:

  • 为什么你不想在生成 A 时将其绑定到 'static 生命周期?我很确定您将必须,基于生成的线程可能比父线程寿命更长的事实。 restriction is pretty non-invasive as well.
  • 我想我不确定'static 在这种情况下的含义。我不想让在make_shoes 中使用的A 被泄露,因为它强制它在程序期间存在。
  • 肯定不会泄露的。基本上,您会将变量的所有权转移给线程,并且不允许该变量对无法保证在程序生命周期内存在的项目有任何引用

标签: rust


【解决方案1】:

std::thread::spawn() 函数在其闭包上声明了 Send + 'static 绑定。此闭包捕获的任何内容都必须满足Send + 'static 界限。在安全的 Rust 中,no 可以解决这个问题。如果要使用该函数将数据传递给其他线程,则必须是'static,句号。

可以使用适当的 API 解除 'static 限制,请参阅 How can I pass a reference to a stack variable to a thread? 示例。

但是,'static 绑定并不像看起来那么可怕。首先,您不能 force 任何事情来做任何有生命周期的事情(你不能 force 任何事情来做任何事情有任何类型的界限)。 Bounds 只是限制了可用于有界类型参数的类型集,仅此而已;如果你试图传递一个类型不满足这些界限的值,编译器将无法编译你的程序,它不会神奇地使这些值“活得更久”。

此外,'static 绑定并不意味着该值必须在程序的持续时间内存在;这意味着该值不得包含具有'static 以外的生命周期的借用引用。换句话说,它是值内可能引用的下限;如果没有引用,则绑定无关紧要。例如,StringVec&lt;u64&gt;i32 满足 'static 界限。

'static 是对spawn() 的一个非常自然的限制。如果它不存在,则传输到另一个线程的值可能包含对父线程堆栈帧的引用。如果父线程在派生线程之前完成,这些引用将变得悬空。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 2017-03-09
    • 1970-01-01
    • 2015-06-26
    • 2015-05-26
    相关资源
    最近更新 更多