サーチ…
前書き
マップは、順序付けられていないキーと値のペアを格納するために使用されるデータ型であるため、特定のキーに関連付けられた値をルックアップすることは非常に効率的です。キーはユニークです。基礎となるデータ構造は、新しい要素に対応するために必要に応じて増加するので、プログラマはメモリ管理について心配する必要はありません。他の言語がハッシュテーブル、辞書、または連想配列と呼ぶものと似ています。
構文
- var mapName map [KeyType] ValueType //マップを宣言する
- var mapName = map [KeyType] ValueType {} //空のマップを宣言して割り当てます
- var mapName = map [KeyType] ValueType {key1:val1、key2:val2} //宣言してマップを割り当てます
- mapName:= make(map [KeyType] ValueType)//デフォルトのサイズマップを宣言して初期化する
- mapName:= make(map [KeyType] ValueType、length)// 長さのサイズマップを宣言して初期化する
- mapName:= map [KeyType] ValueType {} //空のマップを自動的に宣言して割り当てます:=
- mapName:= map [KeyType] ValueType {key1:value1、key2:value2} //マップの自動宣言と割り当て:=
- value:= mapName [key] //キーで値を取得する
- 値、hasKey:= mapName [key] //キーで値を取得する、マップにキーが存在する場合は 'hasKey'は 'true'
- mapName [key] = value //キーで値を設定する
備考
Goには、 ハッシュテーブルを実装する組み込みのmap
タイプが用意されています 。マップは、Goの組み込み連想データ型(他の言語のハッシュまたは辞書とも呼ばれます )です。
マップの宣言と初期化
あなたは、キーワードの使用マップ定義map
そのキーとその値の型が続くが、:
// Keys are ints, values are ints.
var m1 map[int]int // initialized to nil
// Keys are strings, values are ints.
var m2 map[string]int // initialized to nil
マップは参照型であり、いったん定義されるとゼロ値はnil
ます。 nilマップへの書き込みはパニックになり、読み取りは常にゼロ値を返します。
マップを初期化するには、 make
関数を使用します。
m := make(map[string]int)
make
の2パラメータ形式では、マップの初期エントリ容量を指定して、デフォルトの容量を上書きすることができます。
m := make(map[string]int, 30)
あるいは、マップを宣言してゼロ値に初期化し、後でそれにリテラル値を代入すると、構造体をjsonにマーシャリングして空のマップを返す場合に役立ちます。
m := make(map[string]int, 0)
また、マップを作成し、その初期値を中括弧( {}
)で設定することもできます。
var m map[string]int = map[string]int{"Foo": 20, "Bar": 30}
fmt.Println(m["Foo"]) // outputs 20
次のステートメントはすべて、変数が同じ値にバインドされる結果となります。
// Declare, initializing to zero value, then assign a literal value.
var m map[string]int
m = map[string]int{}
// Declare and initialize via literal value.
var m = map[string]int{}
// Declare via short variable declaration and initialize with a literal value.
m := map[string]int{}
マップリテラルを使用して、いくつかの初期のキーと値のペアを持つ新しいマップを作成することもできます 。
キータイプは任意の同等のタイプにすることができます。特に、 これは関数、マップ、およびスライスを除外します 。値の型は、カスタム型またはinterface{}
を含む任意の型にできます。
type Person struct {
FirstName string
LastName string
}
// Declare via short variable declaration and initialize with make.
m := make(map[string]Person)
// Declare, initializing to zero value, then assign a literal value.
var m map[string]Person
m = map[string]Person{}
// Declare and initialize via literal value.
var m = map[string]Person{}
// Declare via short variable declaration and initialize with a literal value.
m := map[string]Person{}
マップの作成
複合リテラルを使用して、単一のステートメントでマップを宣言して初期化することができます。
自動型ショート変数宣言の使用:
mapIntInt := map[int]int{10: 100, 20: 100, 30: 1000}
mapIntString := map[int]string{10: "foo", 20: "bar", 30: "baz"}
mapStringInt := map[string]int{"foo": 10, "bar": 20, "baz": 30}
mapStringString := map[string]string{"foo": "one", "bar": "two", "baz": "three"}
同じコードですが、変数の型はあります:
var mapIntInt = map[int]int{10: 100, 20: 100, 30: 1000}
var mapIntString = map[int]string{10: "foo", 20: "bar", 30: "baz"}
var mapStringInt = map[string]int{"foo": 10, "bar": 20, "baz": 30}
var mapStringString = map[string]string{"foo": "one", "bar": "two", "baz": "three"}
マップに独自の構造体を含めることもできます。
値としてカスタムタイプを使用することができます:
// Custom struct types
type Person struct {
FirstName, LastName string
}
var mapStringPerson = map[string]Person{
"john": Person{"John", "Doe"},
"jane": Person{"Jane", "Doe"}}
mapStringPerson := map[string]Person{
"john": Person{"John", "Doe"},
"jane": Person{"Jane", "Doe"}}
あなたの構造体はマップのキーになることもできます:
type RouteHit struct {
Domain string
Route string
}
var hitMap = map[RouteHit]int{
RouteHit{"example.com","/home"}: 1,
RouteHit{"example.com","/help"}: 2}
hitMap := map[RouteHit]int{
RouteHit{"example.com","/home"}: 1,
RouteHit{"example.com","/help"}: 2}
大カッコ{}
内に値を入力しないだけで、空のマップを作成できます。
mapIntInt := map[int]int{}
mapIntString := map[int]string{}
mapStringInt := map[string]int{}
mapStringString := map[string]string{}
mapStringPerson := map[string]Person{}
マップを変数に割り当てる必要なく、マップを直接作成して使用できます。ただし、宣言とコンテンツの両方を指定する必要があります。
// using a map as argument for fmt.Println()
fmt.Println(map[string]string{
"FirstName": "John",
"LastName": "Doe",
"Age": "30"})
// equivalent to
data := map[string]string{
"FirstName": "John",
"LastName": "Doe",
"Age": "30"}
fmt.Println(data)
マップのゼロ値
map
のゼロ値はnil
で、長さは0
です。
var m map[string]string
fmt.Println(m == nil) // true
fmt.Println(len(m) ==0) // true
nil
マップにキーがなく、キーを追加することもできません。 nil
マップは、読み込み元の場合は空のマップのように動作しますが、書き込まれた場合はランタイムパニックが発生します。
var m map[string]string
// reading
m["foo"] == "" // true. Remember "" is the zero value for a string
_, ok = m["foo"] // ok == false
// writing
m["foo"] = "bar" // panic: assignment to entry in nil map
ゼロ値マップの読み書きを試みるべきではありません。代わりに、マップを使用する前にマップを初期化します( make
または割り当てを使用して)。
var m map[string]string
m = make(map[string]string) // OR m = map[string]string{}
m["foo"] = "bar"
マップの要素を反復する
import fmt
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, value := range people {
fmt.Println("Name:", key, "Age:", value)
}
範囲ループを持つマップを反復処理する場合、反復順序は指定されておらず、ある反復から次の反復まで同じであることが保証されていないことに注意してください。
また、キーを取得するだけでなく、値を取得するだけの場合は、キーまたはマップの値を破棄することもできます。
マップのキーを反復する
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, _ := range people {
fmt.Println("Name:", key)
}
キーを探しているだけの場合は、最初の値であるため、アンダースコアをドロップするだけです。
for key := range people {
fmt.Println("Name:", key)
}
範囲ループを持つマップを反復処理する場合、反復順序は指定されておらず、ある反復から次の反復まで同じであることが保証されていないことに注意してください。
マップ要素を削除する
delete
組み込み関数は、指定されたキーを持つ要素をマップから削除します。
people := map[string]int{"john": 30, "jane": 29}
fmt.Println(people) // map[john:30 jane:29]
delete(people, "john")
fmt.Println(people) // map[jane:29]
map
がnil
か、そのような要素がない場合、 delete
は効果を持ちません。
people := map[string]int{"john": 30, "jane": 29}
fmt.Println(people) // map[john:30 jane:29]
delete(people, "notfound")
fmt.Println(people) // map[john:30 jane:29]
var something map[string]int
delete(something, "notfound") // no-op
地図要素を数える
組み込み関数len
は、 map
内の要素の数を返します
m := map[string]int{}
len(m) // 0
m["foo"] = 1
len(m) // 1
変数がnil
マップを指す場合、 len
は0を返します。
var m map[string]int
len(m) // 0
マップの同時アクセス
goのマップは並行性にとって安全ではありません。同時にアクセスする場合は、ロックを取って読み書きする必要があります。通常、最良の選択肢は、読み書きロックを持つことができるため、 sync.RWMutex
を使用することです。ただし、 sync.Mutex
も使用できます。
type RWMap struct {
sync.RWMutex
m map[string]int
}
// Get is a wrapper for getting the value from the underlying map
func (r RWMap) Get(key string) int {
r.RLock()
defer r.RUnlock()
return r.m[key]
}
// Set is a wrapper for setting the value of a key in the underlying map
func (r RWMap) Set(key string, val int) {
r.Lock()
defer r.Unlock()
r.m[key] = val
}
// Inc increases the value in the RWMap for a key.
// This is more pleasant than r.Set(key, r.Get(key)++)
func (r RWMap) Inc(key string) {
r.Lock()
defer r.Unlock()
r.m[key]++
}
func main() {
// Init
counter := RWMap{m: make(map[string]int)}
// Get a Read Lock
counter.RLock()
_ = counter.["Key"]
counter.RUnlock()
// the above could be replaced with
_ = counter.Get("Key")
// Get a write Lock
counter.Lock()
counter.m["some_key"]++
counter.Unlock()
// above would need to be written as
counter.Inc("some_key")
}
ラッパー関数のトレードオフは、基礎となるマップの公開アクセスと、適切なロックの使用との間で行われます。
スライスを値として持つマップの作成
m := make(map[string][]int)
存在しないキーにアクセスすると、ゼロスライスが値として返されます。 nilスライスは、 append
やその他の組み込み関数で使用するときにゼロ長スライスのように動作するので、通常、キーが存在するかどうかを確認する必要はありません。
// m["key1"] == nil && len(m["key1"]) == 0
m["key1"] = append(m["key1"], 1)
// len(m["key1"]) == 1
マップからキーを削除すると、キーはゼロスライスに戻ります。
delete(m, "key1")
// m["key1"] == nil
マップ内の要素をチェックする
マップから値を取得するには、次のようにする必要があります。00
value := mapName[ key ]
マップにキーが含まれている場合は、対応する値が返されます。
そうでない場合は、マップの値タイプのゼロ値を返します( int
値のマップの場合は0
、 string
値のマップの場合は""
...")
m := map[string]string{"foo": "foo_value", "bar": ""}
k := m["foo"] // returns "foo_value" since that is the value stored in the map
k2 := m["bar"] // returns "" since that is the value stored in the map
k3 := m["nop"] // returns "" since the key does not exist, and "" is the string type's zero value
空の値と存在しないキーを区別するために、マップアクセスの2番目に返された値を使用することができます(同じvalue, hasKey := map["key"]
を使用してvalue, hasKey := map["key"]
)。
この2番目の値はboolean
型で、次のようになります。
- 値がマップ内にある場合は
true
、 - マップに指定されたキーが含まれていない場合は
false
次の例を見てください:
value, hasKey = m[ key ]
if hasKey {
// the map contains the given key, so we can safely use the value
// If value is zero-value, it's because the zero-value was pushed to the map
} else {
// The map does not have the given key
// the value will be the zero-value of the map's type
}
マップの値を反復する
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for _, value := range people {
fmt.Println("Age:", value)
}
範囲ループを持つマップを反復処理する場合、反復順序は指定されておらず、ある反復から次の反復まで同じであることが保証されていないことに注意してください。
地図をコピーする
スライスと同様に、マップは基礎となるデータ構造への参照を保持します 。その値を別の変数に代入することによって、参照のみが渡されます。マップをコピーするには、別のマップを作成して各値をコピーする必要があります。
// Create the original map
originalMap := make(map[string]int)
originalMap["one"] = 1
originalMap["two"] = 2
// Create the target map
targetMap := make(map[string]int)
// Copy from the original map to the target map
for key, value := range originalMap {
targetMap[key] = value
}
マップをセットとして使用する
いくつかの言語は、セットのネイティブ構造を持っています。 Goでセットを作成するには、セットの値タイプから空の構造体( map[Type]struct{}
)にマップを使用することをおmap[Type]struct{}
ます。
たとえば、文字列の場合:
// To initialize a set of strings:
greetings := map[string]struct{}{
"hi": {},
"hello": {},
}
// To delete a value:
delete(greetings, "hi")
// To add a value:
greetings["hey"] = struct{}{}
// To check if a value is in the set:
if _, ok := greetings["hey"]; ok {
fmt.Println("hey is in greetings")
}