Go 言語のマップ (Maps)
1. マップの概要
マップ(Maps)は、データを key:value(キー:値) のペアで格納するために使用されます。
- 各要素は「キー:値」のペアで構成されます。
- マップは順序が保証されず(unordered)、変更可能(changeable)なコレクションです。また、重複したキーを保持することはできません。
- マップの長さは要素の数であり、
len()関数を使用して取得できます。 - マップのデフォルト値(初期値)は
nilです。 - マップは内部的なハッシュテーブルへのリファレンス(参照)を保持します。
Goでは、マップを作成するための複数の方法が用意されています。
2. var と := を使用したマップの作成
2.1. シンタックス
var a = map[KeyType]ValueType{key1:value1, key2:value2,...}
b := map[KeyType]ValueType{key1:value1, key2:value2,...}2.2. 実装例
この例では、Goでのマップ作成方法を示します。コード内の記述順と、出力結果の順序が異なる点に注目してください。
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964"}
b := map[string]int{"Oslo": 1, "Bergen": 2, "Trondheim": 3, "Stavanger": 4}
fmt.Printf("a\t%v\n", a)
fmt.Printf("b\t%v\n", b)
}実行結果:
a map[brand:Ford model:Mustang year:1964]
b map[Bergen:2 Oslo:1 Stavanger:4 Trondheim:3]注意: コード内で定義された要素の順序と、実際に格納される順序は異なります。データは、マップからの効率的な取得を最適化する形で格納されます。
3. make() 関数による作成
3.1. シンタックス
var a = make(map[KeyType]ValueType)
b := make(map[KeyType]ValueType)3.2. 実装例
package main
import ("fmt")
func main() {
var a = make(map[string]string) // マップは現在空です
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
// a は空ではなくなりました
b := make(map[string]int)
b["Oslo"] = 1
b["Bergen"] = 2
b["Trondheim"] = 3
b["Stavanger"] = 4
fmt.Printf("a\t%v\n", a)
fmt.Printf("b\t%v\n", b)
}4. 空のマップの作成
空のマップを作成するには2つの方法があります。一つは make() 関数を使用する方法、もう一つは以下のシンタックスを使用する方法です。
4.1. シンタックス
var a map[KeyType]ValueType 重要: 空のマップを作成する正しい方法は make() 関数 を使うことです。それ以外の方法(リテラルなしの宣言のみ)で作成した空のマップに書き込みを行おうとすると、ランタイムパニックが発生します。
4.2. 宣言の違いの確認
package main
import ("fmt")
func main() {
var a = make(map[string]string)
var b map[string]string
fmt.Println(a == nil) // 結果: false
fmt.Println(b == nil) // 結果: true
}5. キーと値に許可される型
5.1. キーに使用できる型
マップのキーには、比較演算子(==)が定義されている任意のデータ型を使用できます。
- ブーリアン(Booleans)
- 数値(Numbers)
- 文字列(Strings)
- 配列(Arrays)
- ポインタ(Pointers)
- 構造体(Structs)
- インターフェース(Interface:動的な型が比較をサポートしている場合)
5.2. 無効なキーの型
比較演算子が定義されていない以下の型はキーとして使用できません。
- スライス(Slices)
- マップ(Maps)
- 関数(Functions)
5.3. 値に使用できる型
値(Values)にはあらゆる型を使用可能です。
6. 要素へのアクセス
特定のキーを指定して値を取得します。
6.1. シンタックス
value = map_name[key]6.2. 実装例
package main
import ("fmt")
func main() {
var a = make(map[string]string)
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
fmt.Printf(a["brand"])
}7. 要素の更新と追加
要素の更新と追加は、同じシンタックスで行われます。
7.1. シンタックス
map_name[key] = value7.2. 実装例
package main
import ("fmt")
func main() {
var a = make(map[string]string)
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
fmt.Println(a)
a["year"] = "1970" // 要素の更新
a["color"] = "red" // 要素の追加
fmt.Println(a)
}8. 要素の削除
要素の削除には組み込みの delete() 関数を使用します。
8.1. シンタックス
delete(map_name, key)8.2. 実装例
package main
import ("fmt")
func main() {
var a = make(map[string]string)
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
fmt.Println(a)
delete(a, "year")
fmt.Println(a)
}9. キーの存在確認
マップに特定のキーが存在するかどうかを確認するには、以下の書式を使用します。
9.1. シンタックス
val, ok := map_name[key]存在確認だけが必要な場合は、値(val)の代わりにブランク識別子(_)を使用できます。
9.2. 実装例
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964", "day":""}
val1, ok1 := a["brand"] // 存在するキーとその値を確認
val2, ok2 := a["color"] // 存在しないキーを確認
val3, ok3 := a["day"] // 値が空文字列だが存在するキーを確認
_, ok4 := a["model"] // 値は不要で、存在のみを確認
fmt.Println(val1, ok1)
fmt.Println(val2, ok2)
fmt.Println(val3, ok3)
fmt.Println(ok4)
}解説:
キー "color" は存在しないため、val2 は空文字列、ok2 は false になります。一方で "day" は値が空文字列ですが、キー自体は存在するため ok3 は true になります。
10. マップは参照型 (References)
マップはハッシュテーブルへのリファレンス(参照)です。
もし2つのマップ変数が同じハッシュテーブルを参照している場合、一方の内容を変更すると、もう一方の内容も影響を受けます。
10.1. 実装例
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964"}
b := a
fmt.Println(a)
fmt.Println(b)
b["year"] = "1970"
fmt.Println("b を変更した後:")
fmt.Println(a)
fmt.Println(b)
}11. マップの反復処理 (Iterate)
マップの全要素を走査するには range を使用します。
11.1. 実装例
package main
import ("fmt")
func main() {
a := map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}
for k, v := range a {
fmt.Printf("%v : %v, ", k, v)
}
}12. 特定の順序での反復処理
マップは順序を持たないデータ構造です。もし特定の順序で反復処理を行いたい場合は、その順序を指定するための別のデータ構造(スライスなど)を用意する必要があります。
12.1. 実装例
package main
import ("fmt")
func main() {
a := map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}
var b []string // 順序を定義するためのスライス
b = append(b, "one", "two", "three", "four")
for k, v := range a { // 順序が保証されないループ
fmt.Printf("%v : %v, ", k, v)
}
fmt.Println()
for _, element := range b { // 定義した順序に従ったループ
fmt.Printf("%v : %v, ", element, a[element])
}
}