いろは3014035 views
高校日本史190647 views
中学社会669043 views
MathPython498173 views
LaTeX962830 views
中学数学624025 views
小学理科720260 views
雑学1473736 views
中学英語812106 views
高校生物552029 views
Help
Tools

English

Go のマップのイテレーション(for range)

マップの全要素を処理するには for range を使う。スライスのイテレーションと似ているが、いくつか重要な違いがある。

基本的なイテレーション

for range でキーと値を同時に取得できる。

ages := map[string]int{
    "Alice":   30,
    "Bob":     25,
    "Charlie": 35,
}

for name, age := range ages {
    fmt.Printf("%s is %d years old\n", name, age)
}

出力例:

Bob is 25 years old
Alice is 30 years old
Charlie is 35 years old

順序は保証されない

マップのイテレーション順序は不定だ。同じマップでも実行するたびに順序が変わる可能性がある。

for i := 0; i < 3; i++ {
    fmt.Println("--- Run", i+1, "---")
    for k, v := range ages {
        fmt.Println(k, v)
    }
}

Go は意図的にマップの順序をランダム化している。順序に依存したコードを書かないようにするためだ。

キーだけを取得

値が不要な場合は、キーだけを受け取れる。

for name := range ages {
    fmt.Println(name)
}

値だけを取得

キーが不要な場合は、ブランク識別子を使う。

for _, age := range ages {
    fmt.Println(age)
}

ソートしてイテレーション

順序が必要な場合は、キーをスライスに取り出してソートする。

import "sort"

ages := map[string]int{
    "Alice":   30,
    "Bob":     25,
    "Charlie": 35,
}

// キーをスライスに取り出す
names := make([]string, 0, len(ages))
for name := range ages {
    names = append(names, name)
}

// ソート
sort.Strings(names)

// ソート順でイテレーション
for _, name := range names {
    fmt.Printf("%s: %d\n", name, ages[name])
}

出力:

Alice: 30
Bob: 25
Charlie: 35

イテレーション中の変更

イテレーション中に要素を追加・削除することは可能だが、挙動が複雑になる。

m := map[int]bool{1: true, 2: true, 3: true}

for k := range m {
    if k == 2 {
        delete(m, k) // 削除はOK
    }
}
fmt.Println(m) // map[1:true 3:true]

削除は安全に行えるが、追加した要素がそのイテレーションで処理されるかどうかは不定だ。

m := map[int]bool{1: true}

for k := range m {
    m[k+10] = true // 追加
    if k > 100 {
        break // 無限ループ防止
    }
}
// 結果は不定

イテレーション中の追加は避けるか、新しいマップに書き込む方が安全だ。

空のマップのイテレーション

空のマップや nil マップをイテレーションしても panic は起きない。単にループが実行されないだけだ。

var m map[string]int // nil マップ

for k, v := range m {
    fmt.Println(k, v) // 実行されない
}

fmt.Println("Done") // 正常に出力される

これにより、マップが空かどうかを事前にチェックする必要がない。