マップは、インデックス番号の代わりに、キーによって要素を管理するコレクションです。
キーには整数、浮動小数点数なども使えますが、文字列を使うのが一般的です。
マップは、他の言語では、辞書、ハッシュ、連想配列などと呼ばれています。
マップは、インデックス番号で管理されていないので、要素の順序という概念はありません。
マップは、もとのマップに要素の追加と削除ができます。
マップは、参照型のコレクションです。マップ名はポインターとして使えます。
package main
import "fmt"
func main() {
m := make(map [string] int)
var m_ map[string] int
println(m )
println(m_)
fmt.Println(m )
fmt.Println(m_)
m["math"] = 100
//m_["math"] = 100 panic: assignment to entry in nil map というエラーになります
println(m )
fmt.Println(m )
}
0xc00007e000
0x0
map[]
map[]
0xc00007e000
map[math:100]
m := make(map[string] int)
要素のない空のマップの定義は、make 関数と map キーワードを使った簡略定義になります。map キーワードに続く [ と ] の間に、キーの型を指定し、続いて値の型を指定します。このコードでは、string 型のキーと、int 型の値という要素を格納できる、空のマップ(要素のないマップ)が定義されています。
var m_ map[string] int
var を使っても、空のマップを定義できるように見えますが、この定義方法で作ったマップは実際には使用できません。
m["math"] = 100
マップに要素を追加するには、キーを指定し、値を代入するだけです。もしマップに同じキーの要素がある場合は、その要素の値が書き換わりますので注意してください。
//m_["math"] = 100 panic: assignment to entry in nil map というエラーになります
var で定義した、マップ m_ に要素を追加しようとしても、エラーになります。
println(m )
要素を追加する前のマップ m と、要素を追加した後のマップ m は、同じアドレスになります。マップはスライスと違い、もとのマップに要素を追加します。
var で定義したマップ m_ に要素を追加できなかったのは、実態のない(アドレスのない)マップに要素を追加することはできないからです。
var で定義したスライスに append で要素を追加できたのは、append は、実体のある(アドレスのある)新しいスライスを作るからです。
fmt.Println(m )
要素のないマップの値は、map[ ] と表示されます。math 要素を追加したマップは、map[math:100]と表示されます。キーと値は : で区切られます。
package main
import "fmt"
func main() {
score := map [string] int {"math":100, "science":80, "english":60}
fmt.Println(score)
println(score)
println(len(score))
delete(score, "math")
delete(score, "music")
fmt.Println(score)
println(score)
println(len(score))
v1 , exist := score["science"]
println(v1, exist)
v2 , exist := score["english"]
println(v2 , exist)
v_, exist := score["art"]
fmt.Printf("%2d %t\n", v_, exist)
}
map[english:60 math:100 science:80]
0xc000082000
3
map[english:60 science:80]
0xc000082000
2
80 true
60 true
0 false
score := map [string] int {"math":100, "science":80, "english":60}
マップの定義と初期化を同時にする場合には、make 関数は使いません。初期値は、キー : 値という形で要素を記述し、各要素は , (コンマ)で区切り、全体を { と }(波括弧)で囲みます。
println(len(score))
マップでも len 関数は使えます。しかし、cap 関数は使えません。マップには容量という概念はないみたいです。
delete(score, "math")
delete(score, "music")
マップの要素の削除は delete 関数で行います。第 1 引数にマップを、第 2 引数に、削除する要素のキーを指定します。該当する要素が存在していた場合は、その要素を削除し、該当する要素が存在しない場合は、何もしません。
println(score)
println 関数の引数にコレクションを渡した場合は、そのコレクションのアドレスが表示されます。コレクションが参照型の場合は、その変数名をそのまま記述すれば OK ですが、コレクションが値型の場合は、&変数名と変数名の前に &(アンパサンド)を付けなければエラーになります。マップの場合は、変数名をそのまま渡せるので、参照型であることが分かります。
マップのアドレスは、要素を削除する前も後も同じアドレスになります。同じマップであることが分かります。
v1 , exist := score["science"]
上記のように記述すると、マップに、キーの要素が存在するかどうかが分かります。v1 と exist は、任意の変数名です。v1 に要素の値が、exist に要素が存在するかどうかの bool 値が代入されます。
v2 , exist := score["english"]
このコードの場合、値を受ける変数は、なぜか使い回しができません。bool 値を受ける変数は使い回しができます。
fmt.Printf("%2d %t\n", v_, exist)
fmt.Printf 関数のフォーマット文で、bool値の書式指定は、%t です。このような書式指定 %t のことを書式指定子と言います。
package main
import "fmt"
func main() {
score := map [string] int {"math":100, "science":80, "english":60}
for k, v := range score {
fmt.Printf("%10s: %3d\n", k, v)
}
}
math: 100
science: 80
english: 60
第 2 部コレクションでは、配列、スライス、マップを紹介しました。
マップは、同じアドレスに要素の追加と削除ができる参照型です。一番使いやすいように感じます。
スライスは、同じ変数にアドレスに要素の追加はできませんが、参照型です。要素を順序で管理したい場合に便利です。