2017-03-05 53 views
0

嗨我在一个相当简单的测试用例中遇到了生命期问题 我似乎无法理解编译器告诉我什么。 下面的代码粘贴到Rust游乐场。生命期错误我不知道如何解决

关于代码的想法是,Element s串在一起成为一个管道。数据最终会传递给下一个元素。每个阶段都有一个(rx, tx)对,它从前一阶段接收输入并将数据发送到下一阶段。我可以将Element标记为Sync,因为只有一个Element将一次处理一部分数据。

的错误是:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements 
    --> <anon>:56:18 
    | 
56 |   for e in self.elements { 
    |     ^^^^^^^^^^^^^ 
    | 
note: first, the lifetime cannot outlive the lifetime 'a as defined on the body at 53:53... 
    --> <anon>:53:54 
    | 
53 |  pub fn run(&self) -> Vec<thread::JoinHandle<()>> { 
    |             ^
note: ...so that expression is assignable (expected std::vec::Vec<Box<&Element>>, found std::vec::Vec<Box<&'a Element + 'a>>) 
    --> <anon>:56:18 
    | 
56 |   for e in self.elements { 
    |     ^^^^^^^^^^^^^ 
    = note: but, the lifetime must be valid for the static lifetime... 
note: ...so that the type `[[email protected]<anon>:62:41: 64:15 e:Box<&Element>, sender:std::sync::Arc<std::sync::Mutex<std::sync::mpsc::SyncSender<(std::string::String, std::string::String)>>>, receiver:std::sync::Arc<std::sync::Mutex<std::sync::mpsc::Receiver<(std::string::String, std::string::String)>>>]` will meet its required lifetime bounds 
    --> <anon>:62:27 
    | 
62 |    handles.push(thread::spawn(move || { 
    |       ^^^^^^^^^^^^^ 

第一个错误我感到困惑,Element s的定义为 &'a Element所以他们不应告诉他们坚持围绕 沿为Pipeline编译器?

第二个错误我想告诉我Vec<thread::JoinHandle<()>>被告知它取决于终身'a?但我不确定如何表达。

我希望第三个在我纠正前两个后会更有意义。目前我只是不知道它告诉我什么。

use std::sync::{Arc, Mutex}; 
use std::thread; 
use std::result::Result; 
use std::sync::mpsc::{SyncSender, Receiver, sync_channel}; 

pub trait Element: Send + Sync { 
    fn run(&self, output: Arc<Mutex<SyncSender<i32>>>, 
        input: Arc<Mutex<Receiver<i32>>>); 
} 

pub struct TestElement {} 

impl TestElement { 
    pub fn new() -> Self { 
     TestElement {} 
    } 
} 

impl Element for TestElement { 
    fn run(&self, output: Arc<Mutex<SyncSender<i32>>>, 
        input: Arc<Mutex<Receiver<i32>>>) { 
     println!("Hello"); 
    } 
} 

pub struct Pipeline<'a> { 
    elements: Vec<Box<&'a Element>>, 
} 

impl<'a> Pipeline<'a> { 
    pub fn new(name: String) -> Self { 
     Pipeline { 
      elements: Vec::new(), 
     } 
    } 

    pub fn run(&self) -> Vec<thread::JoinHandle<()>> { 
     let mut handles = Vec::with_capacity(self.elements.len()); 

     for e in self.elements { 
      let channel = sync_channel::<i32>(1000); 
      let sender = Arc::new(Mutex::new(channel.0)).clone(); 
      let receiver = Arc::new(Mutex::new(channel.1)).clone(); 

      handles.push(thread::spawn(move || { 
       e.run(sender, receiver); 
      })); 
     } 

     handles 
    } 
} 

fn main() { 
    let mut test_element = TestElement::new(); 
    let mut pipeline = Pipeline::new("example pipeline".to_string()); 

    let handles = pipeline.run(); 
} 
+0

您是否可以进一步简化您的代码?它仍然是一大块代码,当我们只处理一小段代码时,它更容易回答,也更容易理解。谢谢:) –

+0

我试图缩小一点。我可以减少更多,但这将删除一些错误,我不确定是否应该,因为我不知道它们是单独的错误还是全部与一个修复相关。你怎么看 ? –

+0

你为什么使用'Box <&'a Element>'? “Box”已经分配了堆,基本上只是一个指针,因此“Box ”应该足够了。这也可以解决你的一生问题(但照亮其他问题)。还要注意,一个生成的线程可以超越其他的一切,所以'Pipeline :: run()'中产生的线程可以比'Pipeline'对象生存得更长!这不是一个答案,但我希望能够推动正确的方向。 –

回答

1

每个note由编译器报道添加上下文前述错误或警告。这不是一个单独的错误;修复错误会使笔记消失。

现在很不幸,错误信息并不清楚。问题在于,您尝试将e(其类型为Box<&'a Element>)转换为传递给thread::spawn的封闭,但thread::spawn需要一个对于生命周期有效的封闭;即它不包含短于'static的引用(并且'static是可用的最长的生存期:它对应于整个程序的持续时间)。 'a不能保证等于'static,因此是错误。

您的代码无效,因为该线程可能会在引用所指的已被释放后继续运行。

一种可能的解决方案是简单地不使用elements矢量内的引用:使用Vec<Box<Element>>。不过,这只有在你不需要重复使用元素时才有效。

另一种选择是使用线程安全引用计数器(Arc)而不是简单引用。这消除了生命周期问题,但会引入一些运行时间开销。

最后一个选项是使用crossbeamspawnscoped线程。使用此选项,您可以继续使用参考。你无法做的一件事是在作用域结束之前返回连接句柄。您仍然可以从Pipeline::run返回联合手柄,但crossbeam将在scope返回之前加入所有线程。

历史记录:在Rust达到1.0之前,曾经在标准库中实现了作用域线程。但是不是为范围使用闭包,而是简单地返回一个JoinHandle,并且此实现的安全性依赖于调用JoinHandle上的析构函数的程序。如果析构函数未在适当的时间运行(例如,您调用mem::forget),则该线程将继续运行并可能引用释放的对象。 crossbeam仍然依赖于被调用的析构函数,但它的编写使得库的用户永远不能获得Scope的所有权,所以该库可以保证析构函数将被运行。

+0

最后感谢我使用了横梁。多个错误让我感到困惑。 耻辱他们不能将crossbeam重新引入标准库。 –

+0

他们当然可以在标准库中引入crossbeam的功能,但作为外部库开发新功能有几个优点。它为作者提供了更大的灵活性,可以在早期更改API,并为其提供更多的受众,因为标准库中引入的新功能首先作为_unstable_引入,这意味着只有使用夜间编译器的用户才能使用它们。 –

相关问题