我可以运行此代码
fn testf(host: &str) {}
fn start(host: &str) {
testf(host);
testf(host);
}
但出于某种原因,我无法运行这个:
fn testf(host: &str) {}
fn start(host: &str) {
thread::spawn(move || testf(host));
thread::spawn(move || testf(host));
}
因为以下错误
src/server.rs:30:5: 30:18 error: the type `[closure@src/server.rs:30:19: 30:38 host:&str]` does not fulfill the required lifetime
src/server.rs:30 thread::spawn(move || testf(host));
^~~~~~~~~~~~~
note: type must outlive the static lifetime
error: aborting due to previous error
有人可以解释一下,它有什么问题以及如何解决它?
答案 0 :(得分:6)
您的闭包捕获字符串切片,因此其环境的生命周期不会超过此切片的生命周期,但thread::spawn()
要求其参数具有静态生命周期:
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static
(请注意F: 'static
要求)
这是必要的,因为当thread::spawn()
生成的线程运行时,可能已经破坏了从中获取切片的字符串。 Rust实际上阻止了代码中的错误!
有几种方法可以解决它。
1)最简单的方法是克隆每个线程的字符串:
fn start(host: &str) {
{
let host = host.to_owned();
thread::spawn(move || testf(&host));
}
{
let host = host.to_owned();
thread::spawn(move || testf(&host));
}
}
这样每个线程都会收到自己的字符串副本,当线程本身完成时,该副本将被销毁。
2)如果你知道你的线程应该在start()
函数结束之前完成,你可以使用像crossbeam之类的第三方库来将引用传递给生成的线程:
extern crate crossbeam;
fn start(host: &str) {
crossbeam::scope(|scope| {
scope.spawn(move || testf(host));
scope.spawn(move || testf(host));
});
}
这种方式start()
将一直等到scoped()
中的两个线程都在返回之前完成,确保任何字符串host
指向不会过早被销毁。
以前这样的功能包含在标准库中,但它的实现方式是was found to be unsound,所以它已被弃用;正确替换此功能尚未添加回标准库。
3)甚至另一种选择是使用Arc<String>
来共享线程之间的字符串,但这需要在start()
之外进行更重要的更改:
use std::sync::Arc;
fn start(host: Arc<String>) {
{
let host = host.clone();
thread::spawn(move || testf(&host));
}
{
let host = host.clone();
thread::spawn(move || testf(&host));
}
}
使用这种方法,你需要将你的字符串保持在Arc
(这是一个&#34;原子引用计数&#34;指针),所以这要求你改变调用{{1}的代码}。克隆可能更好。当然,如果您想要共享start()
而不是&str
,其中&SomeStruct
很大且/或无法克隆,则无法避免使用xor SomeStruct
作为范围。
答案 1 :(得分:0)
线程声明:: spawn函数试图告诉我有关我的问题:)
pub fn spawn<F, T>(f: F) -> JoinHandle<T> where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
所以,我可以修复使用(host:&amp;&#39; static str)的内容(host:&amp; str)
fn testf(host: &str) {}
fn start(host: &'static str) {
thread::spawn(move || testf(host));
thread::spawn(move || testf(host));
}
它对我很有用