私はRustでレイジー構築/メモ化評価/キャッシュイディオムを実装しようとしています。Rustでselfを使用する構造のマップエントリを作成する方法
動作の仕方は、データの束を持つ外部型とアクセサメソッドです。アクセサメソッドでは、キャッシュされた計算(キャッシュがある場合)を返すか、計算して後で使用できるようにマップに戻り値を格納する必要があります。キャッシュされた値は外側の値を参照する必要がないので、循環参照の問題はありません。それ自体を構築するためには、外側の値のデータにアクセスする必要があります。
ここで錆のボローチェッカーを通らない完全な例です:
use std::collections::HashMap;
pub struct ContainedThing {
count: usize,
}
impl ContainedThing {
fn create(thing: &Thing) -> ContainedThing {
// create uses an arbitrary number of attributes from Thing
// it doesn't keep any references after returning though
let count = thing.map.len();
ContainedThing { count: count }
}
}
struct Thing {
map: HashMap<i32,ContainedThing>,
}
impl Thing {
pub fn get(&mut self, key: i32) -> &ContainedThing {
self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
}
}
fn main() {
}
特定のエラーがこれです:私は良い方法を考え出す本当に苦労してい
test.rs:20:44: 20:46 error: cannot borrow `self` as immutable because `self.map` is also borrowed as mutable [E0502]
test.rs:20 self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
^~
test.rs:20:9: 20:17 note: mutable borrow occurs here
test.rs:20 self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
^~~~~~~~
test.rs:21:5: 21:6 note: mutable borrow ends here
test.rs:21 }
^
test.rs:20:71: 20:75 note: borrow occurs due to use of `self` in closure
test.rs:20 self.map.entry(key).or_insert_with(|| ContainedThing::create(&self))
^~~~
このイディオムを実装する。私は、entry()
APIの代わりにget()
の戻り値に一致するパターンを試しましたが、依然としてmatch
の式もself
の借用終了となります。
私はこのようget
を書き換えることができます。
pub fn get(&mut self, key: i32) -> &ContainedThing {
if !self.map.contains_key(&key) {
let thing = ContainedThing::create(&self);
self.map.insert(key, thing);
}
self.map.get(&key).unwrap()
}
が、これはかなり醜いです(そのunwrap
を見て)、より検索し、コピー必要であるべきだよりを必要としているようです。理想的には、私は
- のように、ハッシュエントリを1回見つけるのにかかる費用のみを支払うようにします。
entry()
が正しく行われた場合は、見つからない場合は挿入位置を追跡する必要があります。 - 新しく構築された値のコピー数を減らします。これは実行不可能かもしれません、理想的には、私はインプレースの構築があります。
- 使用を避けるため
unwrap
;無意味なパターンマッチなしに、それはです。
私の不器用なコードは、達成できる最高のものですか?
http://stackoverflow.com/q/30681468/155423などの複製となる予定です。それが変更されているので、あなたは 'self'を渡すことはできません。 'entry'が' HashMap'への参照を渡したなら、それ以上の検索を行うことができます。 – Shepmaster
@Shepmaster:ラムダの中の参照の使用のために、私は少し違うと言います。ここでの実行順序は問題ありません。ラムダの実行中、ハッシュマップはフリーズされます。 –
'&Thing'を必要とするか、後で計算するために必要なもの(ここで' .len() ')を"抽出 "していますか?あなたはそれから借りを避けるでしょう。したがって、あなたは 'or_insert_with'を使うことができます。 @MatthieuM。 –