HashMap::keys() / values() / iter()
| 対応: | Rust 1.0(2015) |
|---|
『HashMap』のキー・値・キーと値のペアをイテレーションで取り出すメソッドです。ループ処理でマップの内容を順に処理する際に使用します。
構文
// キーの参照を取り出すイテレータを生成します。
for key in map.keys() { }
// 値の参照を取り出すイテレータを生成します。
for value in map.values() { }
// キーと値のペア(タプル)を取り出すイテレータを生成します。
for (key, value) in map.iter() { }
// キーと値の所有権を取り出すイテレータを生成します(mapは消費されます)。
for (key, value) in map.into_iter() { }
メソッド一覧
| メソッド | 概要 |
|---|---|
| keys() | キーの参照を返すイテレータを生成します。値には触れずキーだけを処理したい場合に使います。 |
| values() | 値の参照を返すイテレータを生成します。キーが不要で値だけを処理したい場合に使います。 |
| values_mut() | 値の可変参照を返すイテレータを生成します。ループ内で値を書き換えたい場合に使います。 |
| iter() | キーと値の参照のペア『(&K, &V)』を返すイテレータを生成します。最もよく使う汎用的なイテレーション方法です。 |
| iter_mut() | キーの参照と値の可変参照のペア『(&K, &mut V)』を返すイテレータを生成します。 |
| into_iter() | キーと値の所有権を持つペア『(K, V)』を返すイテレータを生成します。呼び出し後はマップを使用できません。 |
サンプルコード
『keys』『values』『iter』と可変イテレーションの使い方を確認するサンプルコードです。
sample_hashmap_keys_values_iter.rs
use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("岡部倫太郎"), 100);
scores.insert(String::from("牧瀬紅莉栖"), 85);
scores.insert(String::from("椎名まゆり"), 92);
// キーだけをループします。
println!("--- keys ---");
for key in scores.keys() {
println!("{}", key);
}
// 値だけをループします。
println!("--- values ---");
for val in scores.values() {
println!("{}", val);
}
// キーと値のペアをループします。
println!("--- iter ---");
for (name, score) in scores.iter() {
println!("{}: {}", name, score);
}
// 値を可変参照で取り出して書き換えます。
for val in scores.values_mut() {
*val += 5; // 全員のスコアに5点加算します。
}
println!("加算後: {:?}", scores);
}
コンパイルして実行すると次のように出力されます。
rustc hashmap_keys_values_iter.rs
./hashmap_keys_values_iter
--- keys ---
岡部倫太郎
牧瀬紅莉栖
椎名まゆり
--- values ---
100
85
92
--- iter ---
岡部倫太郎: 100
牧瀬紅莉栖: 85
椎名まゆり: 92
加算後: {"岡部倫太郎": 105, "牧瀬紅莉栖": 90, "椎名まゆり": 97}
よくあるミス
よくあるミス1: into_iter() 後にマップを使おうとするコンパイルエラー
『into_iter()』はマップの所有権を消費します。into_iter() を呼んだあとは、元の変数は使用できなくなります。
use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("岡部倫太郎".to_string(), 100);
scores.insert("牧瀬紅莉栖".to_string(), 85);
// into_iter() で所有権を消費する
for (name, score) in scores.into_iter() {
println!("{}: {}", name, score);
}
// コンパイルエラー: scores は既に消費された
// println!("{:?}", scores);
}
use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("岡部倫太郎".to_string(), 100);
scores.insert("牧瀬紅莉栖".to_string(), 85);
// OK: イテレーション後もマップを使いたい場合は iter() を使う
for (name, score) in scores.iter() {
println!("{}: {}", name, score);
}
println!("件数: {}", scores.len()); // まだ使える
}
よくあるミス2: ループ中にマップを変更しようとする
イテレーション中のマップに要素を追加・削除しようとすると、借用ルール違反でコンパイルエラーになります。変更が必要な場合は先にキーを収集してからループします。
use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("椎名まゆり".to_string(), 90);
scores.insert("岡部倫太郎".to_string(), 80);
// コンパイルエラー: iter() で借用中に remove() を呼べない
// for (name, _) in scores.iter() {
// if *name == "椎名まゆり" {
// scores.remove(name); // エラー
// }
// }
// OK: retain() を使って条件を満たすエントリのみ残す
scores.retain(|_, score| *score >= 85);
println!("{:?}", scores);
}
概要
『HashMap』のイテレーションメソッドは、用途に応じて3種類から選びます。キーだけ必要なら『keys()』、値だけなら『values()』、両方必要なら『iter()』を使います。『HashMap』の順序は挿入順ではなくハッシュ値に依存するため、反復順序は実行ごとに異なる場合があります。
値をループ内で変更したい場合は『values_mut()』または『iter_mut()』を使います。また、ループ後にマップ自体が不要な場合は『into_iter()』で所有権ごと取り出すと効率的です。『into_iter()』を使ったあとはマップは使用できなくなる点に注意してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。