2016-10-28 3 views
2

私は最初のRustプロジェクトで最近作業していましたが、私はHashMapStrings〜AtomicUsizeの整数を使用しています。 HashMapは、同時アクセスを可能にするためにRwLockによって保護されています。私はAtomicUsizeの値を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が特に関係していた。それを読んだら、ミューテックスから返された値はミューテックスよりも寿命が短くなければならないことを知ることができます。これは私がやろうとしていることを完全に排除するようです。これが不可能である理由を知ることができます。なぜなら、ハッシュマップへのポインタを持っていて、それがサイズ変更されるミューテックスに値を挿入すると、ぶら下がりポインタがあるからです。

私の質問は2倍です。まず、私が問題を正しく理解しているのか、私がやろうとしたことをやってもいけない理由がもう一つあるのか不思議です。そして、私の第二の質問は、Box原子の整数とそれらをHashMapに保存せずに、私がやろうとしていることを達成するための別の方法があるかどうかです。そのようなアプローチは私にとってはうまくいくようですが、常に有効な値Boxedへのポインタを返すことができるからです。しかし、このアプローチはポインタ間接指定と余分な割り当ての余分なレイヤーを必要とするため、非効率的であるようです。ありがとう!

+0

地図のサイズ変更に加えて、他の誰かが参照を保持しているエントリを単に削除することができます。 –

+0

あなたはまさに正しいです!私の使用例では、キーを削除する必要はありませんが、もちろんコンパイラはそのことを認識しません。 – jeromefroe

答えて

3

MutexGuardよりも寿命の長いものへの参照を返すことができないのは間違いありません。なぜなら、おそらくダングリングポインタにつながるからです。

Boxの内容をラップしても役立ちません。 Boxは所有ポインタであり、リダイレクションとは別に、参照寿命が経過する限り、含まれている値のように振る舞います。結局のところ、あなたがそれへの参照を返した場合、誰かがそれをHashMapから削除し、それを割り当て解除する可能性があります。

あなたが参照して何をしたいのかに応じて、私はオプションのカップルを考えることができます。

  1. 代わりに値をINGのBoxの、Arcでそれらをラップします。 HashMapから取得する場合はArcをクローンし、同時に複数の参照を生存させることができます。

  2. MutexGuardを参照と一緒に返すこともできます。 this questionを参照してください。ちょうどその値を操作して、すぐに参照をドロップしたい場合にはうまくいくでしょう。これは、あなたがそれを終えるまで、ミューテックスを保持したままにします。

+0

フィードバックをいただきありがとうございます。これは非常に役に立ちます!私は、 'MutexGuard'を過ぎて生きていける価値への複数の参照を作成できるようにするため、' Arc'を使うアプローチをとると思います。私の使用の場合、 'HashMap'が挿入されると値を削除する必要はありませんので、' Arc'が必要以上に重いかもしれないのだろうかと思います。 'HashMap'の値へのポインタを格納し、' HashMap'がスコープ内にある限り、参照が有効であることをコンパイラに伝える方法があるのだろうかと思います。私のためにもっと掘り起こすようですね! – jeromefroe

+0

私は今朝もう少しこれに取り組んで、代わりに 'Shared'ポインタを使う[別の解決法](https://play.rust-lang.org/?gist=a1d8df52c3a66f7b6a89a6b448a0a89e&version=nightly&backtrace=0)を思いつきました。 '弧'。それは '安全でない'コードと夜間の錆が必要ですが、それでもかなり興味深いと思います。私はまだベンチマークを実行していないが、少し速くすべきだと思う。 – jeromefroe

関連する問題