HashMap::new() / insert() / get()
| 対応: | Rust 1.0(2015) |
|---|
RustのHashMapはキーと値のペアを格納するコレクションです。『HashMap::new()』で生成し、『insert()』でエントリを追加、『get()』で値を取得します。使用するには『use std::collections::HashMap;』が必要です。
構文
use std::collections::HashMap;
// 空のHashMapを生成します。
let mut map: HashMap<String, i32> = HashMap::new();
// キーと値を追加します(同じキーが存在する場合は上書きします)。
map.insert("user_a".to_string(), 90);
map.insert("user_c".to_string(), 85);
// キーを指定して値を取得します(Option<&V>を返します)。
let val = map.get("user_a"); // Some(&90)
let val = map.get("xxx"); // None
// インデックス演算子でも取得できます(キーが存在しない場合はパニック)。
let val = &map["user_a"]; // &90
メソッド一覧
| メソッド | 概要 |
|---|---|
| HashMap::new() | 空のHashMapを生成します。 |
| HashMap::with_capacity(n) | n要素分のメモリを事前確保してHashMapを生成します。 |
| map.insert(key, value) | キーと値を追加します。既存キーの場合は旧値をSomeで返します。 |
| map.get(&key) | キーに対応する値をOption<&V>で返します。 |
| map.get_mut(&key) | キーに対応する値をOption<&mut V>で返します(変更可能)。 |
| map[&key] | キーに対応する値の参照を返します(存在しない場合はパニック)。 |
| map.len() | エントリ数を返します。 |
| map.is_empty() | HashMapが空かどうかを返します。 |
| map.clear() | 全てのエントリを削除します。 |
サンプルコード
『HashMap』の作成、要素の挿入・取得・上書きの動作を確認するサンプルコードです。
sample_hashmap_new_insert_get.rs
use std::collections::HashMap;
fn main() {
// HashMap を生成して要素を追加します。
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("user_a".to_string(), 90);
scores.insert("user_c".to_string(), 85);
scores.insert("user_e".to_string(), 92);
println!("scores: {:?}", scores);
println!("len: {}", scores.len());
// get() で値を取得します(Option型で返ります)。
match scores.get("user_a") {
Some(score) => println!("user_aのスコア: {}", score),
None => println!("user_aは見つかりません"),
}
// if let でスッキリ書けます。
if let Some(score) = scores.get("user_c") {
println!("user_cのスコア: {}", score);
}
// get() が None の場合の処理です。
let result = scores.get("user_b");
println!("user_bのスコア: {:?}", result); // None
// unwrap_or() でデフォルト値を設定します。
let score = scores.get("user_b").unwrap_or(&0);
println!("user_bのスコア(デフォルト0): {}", score);
// get_mut() で値を変更します。
if let Some(score) = scores.get_mut("user_a") {
*score += 5; // 90 → 95
}
println!("user_a更新後: {:?}", scores.get("user_a"));
// insert() は旧値を返します。
let old = scores.insert("user_c".to_string(), 100);
println!("user_cの旧スコア: {:?}", old); // Some(85)
// イテラブルからHashMapを生成します。
let teams = vec![
("Japan".to_string(), 3),
("USA".to_string(), 5),
("Germany".to_string(), 2),
];
let team_map: HashMap<String, i32> = teams.into_iter().collect();
println!("team_map: {:?}", team_map);
// 文字列のHashMapです。
let label_map: HashMap<String, String> = vec![
("user_a".to_string(), "alpha".to_string()),
("user_c".to_string(), "gamma".to_string()),
("user_e".to_string(), "epsilon".to_string()),
].into_iter().collect();
println!("user_aのラベル: {:?}", label_map.get("user_a"));
}
コンパイルして実行すると次のように出力されます。
rustc hashmap_new_insert_get.rs
./hashmap_new_insert_get
scores: {"user_a": 90, "user_c": 85, "user_e": 92}
len: 3
user_aのスコア: 90
user_cのスコア: 85
user_bのスコア: None
user_bのスコア(デフォルト0): 0
user_a更新後: Some(95)
user_cの旧スコア: Some(85)
team_map: {"Japan": 3, "USA": 5, "Germany": 2}
user_aのラベル: Some("alpha")
よくあるミス
よくあるミス1: インデックス演算子でキーが存在しないときパニックする
『map["key"]』形式でキーが存在しない場合、パニックします。安全に取得するには『get()』を使い Option で受け取ります。
use std::collections::HashMap;
fn main() {
let mut map: HashMap<String, i32> = HashMap::new();
map.insert("user_a".to_string(), 90);
// パニック: キーが存在しない場合はパニックする
// let score = map["user_e"]; // パニック
}
use std::collections::HashMap;
fn main() {
let mut map: HashMap<String, i32> = HashMap::new();
map.insert("user_a".to_string(), 90);
// OK: get() で Option を受け取って安全に処理する
match map.get("user_e") {
Some(score) => println!("スコア: {}", score),
None => println!("見つかりません"),
}
// または unwrap_or() でデフォルト値を使う
let score = map.get("user_e").unwrap_or(&0);
println!("スコア(デフォルト0): {}", score);
}
よくあるミス2: get() の戻り値は &V (参照)であることを忘れる
『get()』は『Option<&V>』(値への参照)を返します。値を比較する際は参照であることを意識する必要があります。
use std::collections::HashMap;
fn main() {
let mut map: HashMap<String, i32> = HashMap::new();
map.insert("user_c".to_string(), 85);
// get() は Option<&i32> を返す(&85)
let result = map.get("user_c");
println!("{:?}", result); // Some(85)
// 値を取り出して比較する場合
if let Some(&score) = map.get("user_c") {
if score > 80 {
println!("高スコア: {}", score);
}
}
// または * で参照を外す
if let Some(score) = map.get("user_c") {
if *score > 80 {
println!("高スコア: {}", *score);
}
}
}
概要
HashMapは順序を保証しないため、同じMapでも出力順序が変わることがあります。順序を保ちたい場合はBTreeMapを使います。
Rustでは文字列キーに『&str』を渡すと『String』キーのHashMapでも検索できます(Borrow trait の仕組みにより)。そのため『map.get("user_a")』のように文字列リテラルで検索できます。
インデックス演算子(map["key"])はキーが存在しない場合パニックします。安全に取得するには必ず『get()』を使い、Optionで受け取ってください。
キーの存在確認・削除・entry APIは『HashMap::contains_key() / remove() / entry()』を、イテレーションは『HashMap::keys() / values() / iter()』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。