关于rust:参数类型的寿命可能不够长(带有线程)

Parameter type may not live long enough (with threads)

这类似于Parameter type是否可能寿命不长?,但是我对解决方案的解释似乎无效。 我最初的简化测试用例是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
        });
    }
}

这给了我错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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特性添加了显式寿命:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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);
        })
    }
}

现在这给了我错误:

1
2
3
4
5
6
7
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特性的生命周期参数。 我在这里做错了什么?


std::thread::spawn()函数在其闭包上声明为Send + 'static绑定。此闭包捕获的所有内容都必须满足Send + 'static边界。安全的Rust无法解决此问题。如果要使用此函数将数据传递到其他线程,则它必须为'static,句点。

可以使用适当的API解除'static限制,请参阅如何将对堆栈变量的引用传递给线程?举个例子

但是,'static绑定并不像看起来那样可怕。首先,您不能强迫任何事情在生命周期的界限内做任何事情(您不能强迫任何事情在任何种类的界限内做任何事情)。边界仅限制了可用于有界类型参数的类型集,仅此而已;如果您尝试传递其类型不满足这些限制的值,则编译器将无法编译您的程序,这将不会神奇地使值"寿命更长"。

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

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