問題の歴史:
Rustでは、一般的に使用されるコレクションの1つがHashMapです — ハッシュテーブルとして実装された連想配列です。Rustの実装の特徴は、所有権とメモリの安全性のルールを厳密に遵守し、特定の条件下でのみスレッドセーフであることです。
問題:
ガーベジコレクションを持つ他の言語とは異なり、RustではHashMapに対する任意の操作(追加、取得、変更)は所有権のルールを遵守する必要があります。たとえば、コレクションの内容にアクティブな参照があるときに変更することはできません。また、挿入時の所有権の問題も発生します:要素は移動するか、クローンされる必要があります。また、競合するアクセスがあるとデータ競合のリスクがあります。
解決策:
get_mutまたはentry APIを使用します。コード例:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("key", 10); if let Some(value) = map.get_mut("key") { *value += 1; } println!("{:?}", map.get("key")); }
主な特徴:
get_mutを通じて値を変更する場合、マップ自体の構造(キーを挿入または削除すること)を変更してはいけません。異なる参照を持つ複数のHashMap要素に同時にアクセスできますか?
いいえ、Rustの標準APIでは許可されていません。HashMap全体に対する排他参照が必要な状況でのみ、イテレーションと変更が可能です。
同じ要素に対してミュータブル参照と非ミュータブル参照を取得しようとするとどうなりますか?
コンパイラは、借用チェッカーのルールを違反するエラーを出します:同じ値のミュータブルおよび非ミュータブル借用を同時に行うことはできません。
entry() APIは新しい要素の挿入のみに機能しますか?
いいえ、Entry APIを使用すると、挿入だけでなく既存の値の変更にもアクセスできます。
map.entry("key").and_modify(|v| *v += 1).or_insert(0);
HashMapの値への参照をグローバル変数に提供し、マップのライフタイムを保証しないこと。
利点:
欠点:
複数スレッドから使用するためにHashMapをArc<Mutex<_>>でラップします。
利点:
欠点: