Go 言語でマップを定義するには、map
キーワードを使用します。
マップを定義する (map)
Go 言語のマップ型は、map[キーの型]値の型
のように表現します。
どこにもスペースをいれないことに注意してください(go fmt
コマンドで自動的にこのようにフォーマットされます)。
例えば、キーの型を string
、値の型を int
とするマップは次のように作成できます。
var m = map[string]int{}
m := map[string]int{} // 関数内ではこの省略形が使える
m := make(map[string]int) // make を使う方法
次のように初期値を指定せずにマップを作成するとゼロ値 (nil) になります。 要素数ゼロのマップとして参照はできますが、要素を追加しようとすると panic が発生します。
var m map[string]int // これはゼロ値 (nil) になる
println(len(m)) // 0
m["maku"] = 14 // panic
配列やスライス と同様、初期値を同時に設定してしまうこともできます(前述の例では初期値を空っぽ {}
にしています)。
下記のように複数行に分けて初期値を記述する場合、最後の要素の後ろのカンマは省略できないことに注意してください。
m := map[string]int{
"maku": 14,
"puni": 7,
"hemu": 10,
}
fmt.Printf("%v\n", m) //=> map[maku:14 puni:7 hemu:10]
マップ要素を参照するときは、配列やスライスと同様に []
を使用してキーを指定します。
存在しないキーを指定して新しい値を設定することもできます。
i := m["maku"] // 既存の要素の取得
m["panyo"] = 20 // 新しい要素を追加
マップの要素を for ループで処理する (range)
マップの要素は、配列やスライスと同様に for ループと range
を使ってひとつずつ取得することができます。
m := map[string]int{
"maku": 14,
"puni": 7,
"hemu": 10,
}
for k, v := range m {
fmt.Printf("key: %s, value: %d\n", k, v)
}
key: maku, value: 14
key: puni, value: 7
key: hemu, value: 10
あるキーが存在するかどうか調べる
マップに存在していないキーを指定すると、値の型の ゼロ値 が返されます(例えば int
型の値であれば 0 です)。
i := m["panyo"] //=> 0
そのため、マップの値を参照してゼロ値が返された場合、「キーが存在しない」のか、あるいは「値として 0 が格納されている」のかを区別することができません。 キーがもともと存在していたのかどうかを判別するには、2 つ目の戻り値として返される bool 値 を参照します。
val, ok := m["maku"]
if ok {
println(val)
} else {
println("見つからない")
}
取得した値を if ブロックの中でしか参照しないのであれば、下記のように変数スコープを限定してしまうのがよいです。
if val, ok := m["maku"]; ok {
println(val)
} else {
println("見つからない")
}
キーの存在のみを調べたいときは、1 つ目の戻り値をアンダースコア (_
) で受け取って無視します。
if _, ok := m["maku"]; ok {
println("あるよ")
}
マップの要素を削除する (delete)
組み込み関数の delete を使用すると、マップから指定したキーの要素を削除することができます。
m := map[string]int{
"maku": 100,
"pani": 200,
}
println(len(m)) //=> 2
println(m["maku"]) //=> 100
delete(m, "maku") // キー "maku" を削除する
println(len(m)) //=> 1(サイズが減っている)
println(m["maku"]) //=> 0(存在しないキーを参照するとゼロ値が返される)
削除しようとしたキーが存在しなかった場合は、何も実行されません(エラーにはなりません)。
マップの値としてマップを持つ
マップの値にマップを持つマップを定義することもできます。
m := map[string]map[string]int{
"maku": {"aaa": 10, "bbb": 20},
"puni": {"aaa": 30, "bbb": 40},
"hemu": {"aaa": 50, "bbb": 60},
}
fmt.Println(m["maku"]["aaa"]) //=> 10
この場合も、型名にはどこにもスペースを入れてはいけません。 若干読みにくいですが、気合いで読み解きましょう。
マップのキーでソートした順に要素を取り出す
Go 言語には、マップをキー順にソートしてループ処理する簡潔な方法はないようです。 以下のサンプルでは、キーのリストを自力で作成し、そのリストをソートしています。
package main
import "fmt"
import "sort"
func main() {
m := map[string]int{
"ccc": 10,
"aaa": 20,
"bbb": 30,
}
// ソート済みのキーリストを作成する
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys) // キーの型が int なら sort.Ints とする
// キーリストの順番通りに値を列挙する
for _, k := range keys {
fmt.Println("key:", k, "value:", m[k])
}
}
$ go run main.go
key: aaa value: 20
key: bbb value: 30
key: ccc value: 10