【问题标题】:How could the result of Arc::clone have a 'static lifetime?Arc::clone 的结果怎么会有一个“静态生命周期”?
【发布时间】:2021-08-29 04:36:50
【问题描述】:

让我们从Arc 的规范示例开始

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let msg = Arc::new(Mutex::new(String::new()));
    let mut handles = Vec::new();
    for _ in 1..10 {
        let local_msg = Arc::clone(&msg);
        handles.push(thread::spawn(move || {
            let mut locked = local_msg.lock().unwrap();
            locked.push_str("hello, world\n");
        }));
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("{}", msg.lock().unwrap());
}

这会按预期编译和运行。然后我意识到Mutex 可能不必存在于堆上,并开始想知道我是否可以摆脱Arc 并只使用对分配在堆栈上的Mutex 的共享引用。这是我的尝试

use std::sync::Mutex;
use std::thread;

fn main() {
    let msg = Mutex::new(String::new());
    let mut handles = Vec::new();
    for _ in 1..10 {
        let local_msg = &msg;
        handles.push(thread::spawn(move || {
            let mut locked = local_msg.lock().unwrap();
            locked.push_str("hello, world\n");
        }));
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("{}", msg.lock().unwrap());
}

不过这个不能编译

error[E0597]: `msg` does not live long enough
  --> src/main.rs:8:25
   |
8  |           let local_msg = &msg;
   |                           ^^^^ borrowed value does not live long enough
9  |           handles.push(thread::spawn(move || {
   |  ______________________-
10 | |             let mut locked = local_msg.lock().unwrap();
11 | |             locked.push_str("hello, world\n");
12 | |         }));
   | |__________- argument requires that `msg` is borrowed for `'static`
...
20 |   }
   |   - `msg` dropped here while still borrowed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
error: could not compile `hello`

To learn more, run the command again with --verbose.

编译器抱怨local_msg 没有'static 生命周期。好吧,它没有,所以这个错误是有道理的。但是,这意味着第一个 sn-p 中的变量 let local_msg = Arc::clone(&msg); 具有 'static 生命周期,否则我应该会得到类似的错误。

问题:

  • Arc::clone(&msg) 如何获得'static 的生命周期?它指向的值在编译时是未知的,并且可能在整个程序退出之前死亡。
  • 另外,像BoxRc 这样的其他堆支持的智能指针呢?它们是否都具有'static 生命周期,因为借用检查器确保只要这些指针可见,它们指向的地址就始终有效?

【问题讨论】:

  • "它指向的值在编译时是未知的,并且可能在整个程序退出之前就死掉" - 但它不会在 Arc 本身死掉之前就死掉,这就是重要的.
  • T: 'static 并不意味着T 会一直存在到程序结束,而是它的所有者可以随心所欲地保留它。为此,T 必须包含拥有的数据,例如 String 并且 如果 它包含引用,那么它们必须具有 'static 生命周期。

标签: asynchronous rust closures lifetime borrow-checker


【解决方案1】:

编译器正在寻找的是一个生命周期绑定。 'a 的生命周期边界并不意味着“这个类型是一个生命周期 'a 的引用”,而是“所有此类型包含的引用的生命周期至少 'a”。

(当显式写入生命周期边界时,它看起来像where T: 'a。)

因此,不包含任何引用(或者更确切地说,没有生命周期参数)的任何类型都会自动满足'static 生命周期界限。如果T: 'static,则Arc<T>: 'staticBoxRc 也是如此)。

Arc::clone(&msg) 如何获得“静态生命周期”?它指向的值在编译时是未知的,并且可能在整个程序退出之前就死掉了。

它不指向值使用引用,所以没关系。你的值的类型是Arc<Mutex<String>>;这里没有生命周期参数,因为没有引用。如果是,假设是Arc<'a, Mutex<String>>Arc 实际上没有的生命周期参数),那么该类型将不满足界限。

Arc(或RcBox)的工作是拥有它所指向的价值。所有权不是参考,因此不受生命周期的影响。

但是,如果您有 Arc<Mutex<&'a str>> 类型,那么它不会满足界限,因为它包含一个不是 'static 的引用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-03
    • 2019-08-05
    • 2011-06-14
    • 1970-01-01
    • 2011-09-12
    • 1970-01-01
    相关资源
    最近更新 更多