2016-10-28 22 views
2

我一直在努力研究最近的第一個Rust項目,但遇到了麻煩。我正在使用HashMap映射String s到AtomicUsize整數。 HashMapRwLock保護以允許併發訪問。我希望能夠返回值HashMap中的引用,但是,如果我嘗試將這些引用返回給調用方,並且過了RwLockWriteGuard的生存期,則會出現borrowed value does not live long enough的錯誤。我已經複製了下面的一個簡單例子,並在Rust遊樂場here上放置了相同的示例。試圖從RwLock返回引用,「借來的值不夠長」錯誤

use std::collections::HashMap; 
use std::sync::RwLock; 
use std::sync::atomic::{AtomicUsize, Ordering}; 

struct Bar { 
    val: AtomicUsize 
} 

impl Bar { 
    pub fn new() -> Self { 
     Bar { val: AtomicUsize::new(0) } 
    } 
} 

struct Foo { 
    map: RwLock<HashMap<String, Bar>> 
} 


impl Foo { 
    pub fn get(&self, key: String) -> &Bar { 
     self.map.write().unwrap().entry(key).or_insert(Bar::new()) 
    } 
} 

fn main() { 
    let foo = Foo {map: RwLock::new(HashMap::new())}; 
    let bar = foo.get("key".to_string()); 
} 

我得到的錯誤就行發生:

self.map.write().unwrap().entry(key).or_insert(Bar::new()) 

而且是因爲借來的價值不活足夠長的時間。我讀過幾篇討論這個錯誤的帖子,特別是one尤其相關。讀完它後,我可以得知,互斥量返回的值必須小於互斥量,這似乎完全排除了我正在嘗試執行的操作。我可以看到爲什麼這是不可能的,因爲如果我們有一個指向Hashmap的指針,另一個將值插入互斥量中導致它被調整大小,那麼我們將有一個懸掛指針。

我的問題是雙重的。首先,我只是好奇,如果我正確地理解了這個問題,或者是否有另一個原因讓我不能做我想做的事情?而我的第二個問題是,如果沒有Box原子整數並將那些存儲在HashMap中,是否有另一種方法可以實現我試圖執行的操作?這樣的方法似乎應該對我有用,因爲我們可以返回一個指向Boxed值的指針,該值始終有效。然而,這種方法似乎效率不高,因爲它需要額外的指針間接層和額外的分配。謝謝!

+0

除了地圖大小調整之外,其他人可以簡單地刪除您持有引用的條目。 –

+0

你完全正確!對於我的用例,我不需要永遠刪除一個密鑰,但編譯器當然不知道這一點。 – jeromefroe

回答

3

你是正確的,你不能返回一個超過MutexGuard的東西的引用,因爲這會導致一個可能懸空的指針。但是,將Box中的內容包裝起來並不會有幫助! A Box是一個擁有的指針,除了重定向的行爲就像包含的值一樣,就參考生命週期而言。畢竟,如果您返回了對其的引用,其他人可能會將其從HashMap中刪除並取消分配。

根據您希望與參考做什麼,我能想到幾個選項:

  1. 荷蘭國際集團的值,而不是Box,包起來Arc。從HashMap中抽取Arc時,您可以克隆Arc,並且多個參考可以同時存在。

  2. 您也可以返回MutexGuard以及參考;請參閱this question,如果您只想對該值進行操作,然後相對較快地刪除該參考值,那麼該功能將運行良好。這將保持互斥鎖一直持續到你完成它。

+0

感謝您的反饋,這非常有幫助!我想我會採用使用'Arc'開始的方法,因爲我希望能夠創建多個可以超越'MutexGuard'的值的引用。對於我的用例,我不需要在插入'HashMap'後刪除任何值,所以我想知道'Arc'可能比我需要的更重。我想知道是否存在一種方法來存儲指向'HashMap'中的值的指針,然後使用生存期來告訴編譯器,只要'HashMap'在範圍內,引用就是有效的。似乎更多挖掘我! – jeromefroe

+0

今天早上我又多了一個工作,想出了一個[不同的解決方案](https://play.rust-lang.org/?gist=a1d8df52c3a66f7b6a89a6b448a0a89e&version=nightly&backtrace=0),它使用'Shared'指針代替'Arc'。它需要'不安全的'代碼和每晚Rust,但我認爲它很有趣。我還沒有運行任何基準,但我認爲它應該快一點。 – jeromefroe