Go言語(golang) map の初期化と使い方
連想配列(他言語のhashやdict)は、Go言語では map です。
目次
マップの初期化
初期化時にキーと値のセットを一度に行う
m := map[string]int{"foo": 100, "bar": 200, "baz": 300} // キーの値を取り出すには m[キー名] とする fmt.Println(m["foo"]) // 100 fmt.Println(m["bar"]) // 200 fmt.Println(m["baz"]) // 300
makeを使って初期化
make で map を初期化する場合の第二引数には、キャパシティ(容量)を指定。 キャパシティを指定しない場合は必要十分なキャパシティが自動的に確保される。
m := make(map[string]int, 3) // キャパシティは省略可能 // m := make(map[string]int) m["foo"] = 100 m["bar"] = 200 m["baz"] = 300 fmt.Println(m["foo"]) // 100 fmt.Println(m["bar"]) // 200 fmt.Println(m["baz"]) // 300
マップリテラルで初期化
この場合もキャパシティは自動で確保される。
m := map[string]int{} m["foo"] = 100 m["bar"] = 200 m["baz"] = 300 fmt.Println(m["foo"]) // 100 fmt.Println(m["bar"]) // 200 fmt.Println(m["baz"]) // 300
map を使う場合によくあるエラー (assignment to entry in nil map)
マップを初期化していない状態(nil)で値をセットするとパニックする。
panic: assignment to entry in nil map
なのでvarで宣言しただけの場合には注意する必要がある。
var m map[string]int // 初期化していない状態で値をセットしようとするとパニックする m["key"] = 100
マップが nil かどうか確認してから初期化するか予め初期化しておく
var m map[string]int if m == nil { m = make(map[string]int) } m["key"] = 100
基本的な使い方
追加
m[キー名] = 値
で追加できる。
m := map[string]int{} m["bar"] = 200 fmt.Println(m["bar"]) // 200
値の変更
同じキー名に値を代入することで変更することができる。
m := map[string]int{"foo": 10} fmt.Println(m["foo"]) // 10 変更前 // 値の変更 m["foo"] = 1000 fmt.Println(m["foo"]) // 1000
削除
ビルトイン関数 delete
にマップと削除するキー名を指定する。
m := map[string]int{"foo": 100} // 第一引数に map を指定、第二引数に キー名を指定する delete(m, "foo") _, isThere := m["foo"] fmt.Println(isThere) // false
map 自体の削除
nil
にするだけ。
削除後にキーと値をセットしようとするとエラーになるので、また同じ変数を使う場合は初期化する必要がある。
m := map[string]int{"foo": 100, "bar": 200, "baz": 300} // nil を代入して削除 m = nil fmt.Println(len(m))
キーの個数
配列と同じで len
を使う
m := map[string]int{"foo": 100, "bar": 200, "baz": 300} fmt.Println(len(m)) // 3
キーの存在確認
2つ目の変数が真偽値になっているのでそれで確認できる。
m := map[string]int{"foo": 100} // それぞれキーの値と、キーが存在するかを示す真偽値(bool) value, isThere := m["foo"] fmt.Println(value, isThere) // 100, true // キーが存在しなければ false value, isThere = m["bar"] fmt.Println(value, isThere) // 0, false
キーのみ取得
go言語の map には m.keys()
のような便利な関数はないので for range で愚直にキーをスライスにする
m := map[string]int{"foo": 100, "bar": 200, "baz": 300} // append を使うより make で長さと容量を指定して // keys[i] = key とした方がメモリの再割当てがないので実行速度が速くなる keys := make([]string, len(m), len(m)) i := 0 for key := range m { keys[i] = key i++ } fmt.Println(keys) // [bar baz foo] ※注意: キーの順番は保証されない
map のループ
for ... range
m := map[string]int{"foo": 100, "bar": 200, "baz": 300} // キーのみ取り出す for key := range m { fmt.Println(key) } // キーと値 for key, value := range m { fmt.Println(key, value) } // 値のみ必要な場合 for _, value := range m { fmt.Println(value) } // ループの回数を数える i := 0 for key, value := range m { fmt.Println(key, value) i++ }
キーでソートして順番通りに列挙する
キーをスライス(配列)にして、それをソートする。
そのソートしたキーのスライスを使って何らかの順序でマップの値を取り出す。
m := map[string]int{"B": 100, "C": 200, "A": 300} a := make([]string, len(m), len(m)) i := 0 for key := range m { a[i] = key i++ } // キーを入れたスライスをソートする sort.Strings(a) for i := 0; i < len(a); i++ { fmt.Println(a[i], m[a[i]]) }
2つのマップが同じかどうか確認
reflect.DeepEqual
を使って2つのマップがどちらも同じキーと値を持っているか調べる。
package main import ( "fmt" "reflect" ) func main() { m1 := map[string]int{"A": 100, "B": 200, "C": 300} m2 := map[string]int{"B": 200, "C": 300, "A": 100} isSame := reflect.DeepEqual(m1, m2) fmt.Println(isSame) // true // 値が異なるマップ m3 := map[string]int{"C": 100, "B": 300, "A": 200} isSame = reflect.DeepEqual(m1, m3) fmt.Println(isSame) // false }
キーの型
rune (int32)
m := map[rune]int{} m['あ'] = 100 println(m['あ']) // 100
真偽値
m := map[bool]string{ true: "value-1", false: "value-2", } println(m[10/2 == 5]) // value-1
ポインター
m := map[*string]int{} key1 := "key" key2 := "key" key3 := "key" m[&key1] = 100 m[&key2] = 200 m[&key3] = 300 for k, v := range m { fmt.Println(*k, v) }
インターフェイス
m := map[interface{}]int{} m[interface{}("key")] = 100 m[interface{}(true)] = 200 m[interface{}(300)] = 300 println(m[interface{}("key")]) // 100 println(m[interface{}(true)]) // 200 println(m[interface{}(300)]) // 300
構造体
type Key struct { name string } m := map[Key]int{} m[Key{"foo"}] = 100 m[Key{"bar"}] = 100 m[Key{"baz"}] = 100 for k, v := range m { println(k.name, v) }