12

我目前正在为 Rust (1.0) 中的生命周期而苦苦挣扎,尤其是在通过通道传递结构时。

我如何得到这个简单的例子来编译:

use std::sync::mpsc::{Receiver, Sender};
use std::sync::mpsc;
use std::thread::spawn;
use std::io;
use std::io::prelude::*;

struct Message<'a> {
    text: &'a str,
}

fn main() {
    let (tx, rx): (Sender<Message>, Receiver<Message>) = mpsc::channel();

    let _handle_receive = spawn(move || {
        for message in rx.iter() {
            println!("{}", message.text);
        }
    });

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let message = Message {
            text: &line.unwrap()[..],
        };
        tx.send(message).unwrap();
    }
}

我得到:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:23:20
   |
23 |             text: &line.unwrap()[..],
   |                    ^^^^^^^^^^^^^ does not live long enough
...
26 |     }
   |     - temporary value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

我可以明白为什么会这样(line仅适用于一次迭代for),但我无法弄清楚这样做的正确方法是什么。

  • 正如编译器提示的那样,我是否应该尝试将 转换&str&'static str
  • 'static如果每一行都有一生,我会泄漏内存吗?
  • 我什么时候应该使用'static呢?这是我应该尽量避免的事情还是完全可以?
  • 有没有更好的方法String通过通道在结构中传递 s?

我为那些幼稚的问题道歉。我已经花了很长时间搜索,但我无法完全理解它。这可能是我的动态语言背景妨碍了:)

顺便说一句:是&input[..]为了将 aString转换为&str考虑好的?这是我能找到的唯一稳定的方法。

4

2 回答 2

15

除非泄漏内存,否则您无法转换&'a T为。&'static T幸运的是,这根本没有必要。没有理由向线程发送借来的指针并将行保留在主线程上。您不需要主线程上的行。只需发送线路本身,即发送String

如果需要从多个线程进行访问(并且您不想克隆),请使用Arc<String>(将来Arc<str>也可以使用)。这样,字符串在线程之间共享,正确共享,以便在没有线程不再使用它时准确地释放它。

在线程之间发送非'static引用是不安全的,因为您永远不知道另一个线程将继续使用它多长时间,因此您不知道借用何时到期并且可以释放对象。请注意,作用域线程没有这个问题(不在 1.0 中,但正如我们所说的那样正在重新设计)确实允许这样做,但常规的spawned 线程可以。

'static不是你应该避免的事情,它的作用完全没问题:表示一个值在程序运行的整个持续时间内都存在。但是,如果这不是您要传达的内容,那当然是错误的工具。

于 2015-05-31T20:51:45.067 回答
2

这样想:线程没有语法生命周期,即线程不会在创建它的代码块的末尾被丢弃。无论您向线程发送什么数据,您都必须确保它与线程一样长,这意味着永远。这意味着'static

在您的情况下可能出现的问题是,如果主循环发送对线程的引用并在线程处理之前销毁字符串。线程在处理字符串时会访问无效内存。

一种选择是将您的行放入某个静态分配的容器中,但这意味着您永远无法销毁这些字符串。一般来说是个坏主意。另一种选择是思考:主线程在读取后​​是否真的需要该行?如果主线程将行的责任转移给处理线程怎么办?

struct Message {
    text: String,
}
for line in stdin.lock().lines() {
    let message = Message {
        text: line.unwrap(),
    };
    tx.send(message).unwrap();
}

现在您正在将所有权(移动)从主线程转移到处理程序线程。因为您移动了您的价值,所以不涉及任何参考,也不再适用终身检查。

于 2019-02-04T02:20:39.007 回答