2017-03-05 54 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_引入,這意味着只有使用夜間編譯器的用戶才能使用它們。 –

相關問題