2015-08-18 26 views
1

如何在一個互斥體中的數據上返回一個迭代器,該互斥體本身包含在結構中。編譯器給出的錯誤是「借來的價值不夠長」。借用互斥量的數據「借用的值不夠長」

如何獲取值的生命週期以擴展到外部範圍?

這是我試圖實現的最小的演示。

use std::sync::{Mutex, Arc}; 
use std::vec::{Vec}; 
use std::slice::{Iter}; 

#[derive(Debug)] 
struct SharedVec { 
    pub data: Arc<Mutex<Vec<u32>>>, 
} 

impl SharedVec { 
    fn iter(& self) -> Iter<u32> { 
    self.data.lock().unwrap().iter() 
    } 
} 

fn main() { 

    let sv = SharedVec { 
    data: Arc::new(Mutex::new(vec![1, 2, 3, 4, 5])) 
    }; 

    for element in sv.data.lock().unwrap().iter() { // This works 
    println!("{:?}", element); 
    } 

    for element in sv.iter() { // This does not work 
    println!("{:?}", element); 
    } 
} 

鏽操場鏈接:http://is.gd/voukyN

回答

7

你不能這樣做究竟如何,你都寫在這裏。

Rust中的Mutex使用RAII模式進行採集和釋放,也就是說,當您調用相應的方法時會獲得一個互斥量,該方法會返回一個特殊的保護值。當這個守衛超出範圍時,互斥體被釋放。

爲了使此模式安全,Rust使用其借用系統。您只能通過lock()返回的守護程序訪問互斥量中的值,並且您只能通過引用來執行此操作 - MutexGuard<T> implements Deref<Target=T>DerefMut<Target=T>,因此您可以從中獲得&T&mut T

這意味着你從一個互斥值派生出來的每個值必然有其生命週期與護衛的生命週期相關聯。但是,在您的情況下,您嘗試返回Iter<u32>,其壽命參數與self的壽命相關聯。以下是iter()方法的完整簽名,無一生參數省音,它的機身採用明確的臨時變量:

fn iter<'a>(&'a self) -> Iter<'a, u32> { 
    let guard = self.data.lock().unwrap(); 
    guard.iter() 
} 

這裏guard.iter()結果壽命是聯繫在一起的一個guard,這是嚴格小於'a因爲guard只存在於方法體的範圍內。這違反了借用規則,所以編譯器會因爲錯誤而失敗。

iter()返回時,guard被銷燬並鎖定被釋放,所以Rust實際上阻止了你製造實際的邏輯錯誤! C++中的相同代碼會編譯並且行爲不正確,因爲您將訪問受保護的數據而不鎖定它,至少導致數據競爭。只是Rust的力量的另一個演示:)

我不認爲你能夠做到你想要的,而不會在標準類型周圍出現討厭的黑客或樣板包裝。我個人認爲這很好 - 你必須儘可能明確地管理你的互斥鎖,以避免死鎖和其他討厭的併發問題。而且Rust已經讓你的生活變得更加輕鬆,因爲它通過借用系統來強制數據競速的缺失,這就是守衛系統如上所述的原因。

+0

謝謝你的詳細解釋。 – Luke