2015-11-09 49 views
8

Why can't I store a value and a reference to that value in the same struct?我瞭解到,我無法在同一個結構中存儲值和引用。如何建立一個雙向映射而不煩人借用檢查器?

提出的解決方案是:

的最簡單和最值得推薦的解決方案是不要試圖把這些物品在同一結構在一起。通過這樣做,你的結構嵌套將模仿你的代碼的生命週期。 將擁有數據的類型放置在一個結構中,然後提供允許您根據需要獲取引用或包含引用的對象的方法。

不過,我不知道如何在我的具體案件,不適用此:

我要建立雙向映射,由兩個內部HashMap小號來實現。顯然,其中一個必須擁有這些數據。然而,另一部分對於雙向映射也是必不可少的,所以我沒有看到如何在保持雙向映射接口的同時將這兩者分開。

struct BidiMap<'a, S: 'a, T: 'a> { ? } 
fn put(&mut self, s: S, t: T) ->() 
fn get(&self, s: &S) -> T 
fn get_reverse(&self, t: &T) -> S 

回答

10

在這種情況下,最簡單的解決是像一個垃圾收集語言將工作:

use std::collections::HashMap; 
use std::rc::Rc; 
use std::hash::Hash; 
use std::ops::Deref; 

struct BidiMap<A, B> { 
    left_to_right: HashMap<Rc<A>, Rc<B>>, 
    right_to_left: HashMap<Rc<B>, Rc<A>>, 
} 

impl<A, B> BidiMap<A, B> 
where 
    A: Eq + Hash, 
    B: Eq + Hash, 
{ 
    fn new() -> Self { 
     BidiMap { 
      left_to_right: HashMap::new(), 
      right_to_left: HashMap::new(), 
     } 
    } 

    fn put(&mut self, a: A, b: B) { 
     let a = Rc::new(a); 
     let b = Rc::new(b); 
     self.left_to_right.insert(a.clone(), b.clone()); 
     self.right_to_left.insert(b, a); 
    } 

    fn get(&self, a: &A) -> Option<&B> { 
     self.left_to_right.get(a).map(Deref::deref) 
    } 

    fn get_reverse(&self, b: &B) -> Option<&A> { 
     self.right_to_left.get(b).map(Deref::deref) 
    } 
} 

fn main() { 
    let mut map = BidiMap::new(); 
    map.put(1, 2); 
    println!("{:?}", map.get(&1)); 
    println!("{:?}", map.get_reverse(&2)); 
} 

當然,你想有多少嚴格代碼,因爲這可以讓你打破雙向映射。這只是向您展示解決問題的一種方式。

顯然,其中一人有自己的數據

顯然,這不是真正的^ _ ^。在這種情況下,兩張地圖共享所有權使用Rc

Benchmark此解決方案知道它是否足夠有效。

做更有效率的事情需要更多的關於所有權的思考。例如,如果left_to_right地圖擁有數據,並且您在另一個地圖中使用了一個原始指針,那麼只要重新分配第一個地圖,該指針就會失效。

+0

如果因爲需要修改其中一個值而想要獲取可變引用,該怎麼辦? – khc

+1

@khc然後你需要[內部可變性](https://doc.rust-lang.org/stable/std/cell/)。 – Shepmaster