開発者ドキュメント

Goのマップを理解する

最新のプログラミング言語のほとんどは、辞書またはハッシュタイプの概念を持っています。 これらのタイプは通常、にマップされるキーとペアでデータを格納するために使用されます。

Goでは、 map データ型は、ほとんどのプログラマーが辞書型と考えるものです。 キーを値にマップし、Goにデータを保存するための便利な方法であるキーと値のペアを作成します。 キーワードを使用して地図を作成します map 角かっこで囲まれたキーデータ型が続きます [ ]、その後に値のデータ型が続きます。 次に、キーと値のペアが両側の中括弧内に配置されます{}:

map[key]value{}

通常、Goのマップを使用して、IDに含まれる情報などの関連データを保持します。 データを含むマップは次のようになります。

map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

中括弧に加えて、キーと値のペアを接続するコロンもマップ全体にあります。 コロンの左側の単語がキーです。 キーは、Goの比較可能なタイプであればどれでもかまいません。 strings, ints、 等々。

サンプルマップのキーは次のとおりです。

コロンの右側の単語は値です。 値は任意のデータ型にすることができます。 サンプルマップの値は次のとおりです。

他のデータ型と同様に、マップを変数内に格納して、出力することができます。

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
fmt.Println(sammy)

これはあなたの出力になります:

Output
map[animal:shark color:blue location:ocean name:Sammy]

キーと値のペアの順序がずれている可能性があります。 Goでは、マップデータ型は順序付けされていません。 順序に関係なく、キーと値のペアはそのまま残り、それらの関係の意味に基づいてデータにアクセスできるようになります。

マップアイテムへのアクセス

関連するキーを参照することで、マップの値を呼び出すことができます。 マップはデータを保存するためのキーと値のペアを提供するため、Goプログラムで重要かつ有用なアイテムになる可能性があります。

サミーのユーザー名を分離したい場合は、 sammy["name"]; マップと関連するキーを保持する変数。 それを印刷してみましょう:

fmt.Println(sammy["name"])

そして、出力として値を受け取ります。

Output
Sammy

マップはデータベースのように動作します。 スライスの場合のように整数を呼び出して特定のインデックス値を取得する代わりに、キーに値を割り当て、そのキーを呼び出して関連する値を取得します。

キーを呼び出すことによって "name" そのキーの値を受け取ります。 "Sammy".

同様に、残りの値を呼び出すことができます sammy 同じ形式を使用したマップ:

fmt.Println(sammy["animal"])
// returns shark

fmt.Println(sammy["color"])
// returns blue

fmt.Println(sammy["location"])
// returns ocean

マップデータ型のキーと値のペアを利用することで、キーを参照して値を取得できます。

キーと値

一部のプログラミング言語とは異なり、Goにはマップのキーまたは値を一覧表示する便利な関数がありません。 この例は、Pythonの .keys() 辞書の方法。 ただし、を使用して反復することはできます range オペレーター:

for key, value := range sammy {
	fmt.Printf("%q is the key for the value %q\n", key, value)
}

Goでマップを範囲指定すると、2つの値が返されます。 最初の値がキーになり、2番目の値が値になります。 Goは、これらの変数を正しいデータ型で作成します。 この場合、マップキーは string それで key 文字列にもなります。 The value 文字列でもあります:

Output
"animal" is the key for the value "shark" "color" is the key for the value "blue" "location" is the key for the value "ocean" "name" is the key for the value "Sammy"

キーだけのリストを取得するには、範囲演算子を再度使用できます。 キーにのみアクセスする変数を1つだけ宣言できます。

keys := []string{}

for key := range sammy {
	keys = append(keys, key)
}
fmt.Printf("%q", keys)

プログラムは、キーを格納するスライスを宣言することから始まります。

出力には、マップのキーのみが表示されます。

Output
["color" "location" "name" "animal"]

繰り返しますが、キーはソートされていません。 それらを並べ替える場合は、 sort.Strings sort パッケージの関数:

sort.Strings(keys)

この関数を使用すると、次の出力を受け取ります。

Output
["animal" "color" "location" "name"]

同じパターンを使用して、マップ内の値のみを取得できます。 次の例では、割り当てを回避するためにスライスを事前に割り当てて、プログラムをより効率的にします。

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

items := make([]string, len(sammy))

var i int

for _, v := range sammy {
	items[i] = v
	i++
}
fmt.Printf("%q", items)

まず、キーを保存するスライスを宣言します。 必要なアイテムの数がわかっているので、スライスをまったく同じサイズで定義することで、潜在的なメモリ割り当てを回避できます。 次に、インデックス変数を宣言します。 キーが必要ないので、 _ 演算子は、ループを開始するときに、キーの値を無視します。 出力は次のようになります。

Output
["ocean" "Sammy" "shark" "blue"]

マップ内のアイテムの数を決定するには、組み込みのを使用できます len 関数:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
fmt.Println(len(sammy))

出力には、マップ内のアイテムの数が表示されます。

Output
4

Goにはキーと値を取得するための便利な関数が付属していませんが、必要なときにキーと値を取得するのに数行のコードしか必要ありません。

存在を確認する

要求されたキーが欠落している場合、Goのマップはマップの値タイプのゼロ値を返します。 このため、保存されているゼロと欠落しているキーを区別する別の方法が必要です。

存在しないことがわかっているマップの値を調べて、返された値を見てみましょう。

counts := map[string]int{}
fmt.Println(counts["sammy"])

次の出力が表示されます。

Output
0

キーなのに sammy マップになかった、Goはまだの値を返しました 0. これは、値のデータ型が int、およびGoはすべての変数に対してゼロ値を持っているため、次のゼロ値を返します。 0.

多くの場合、これは望ましくなく、プログラムのバグにつながる可能性があります。 マップで値を検索すると、Goは2番目のオプションの値を返すことができます。 この2番目の値は bool そして true キーが見つかった場合、または false キーが見つからなかった場合。 Goでは、これは ok 熟語。 2番目の引数をキャプチャする変数に任意の名前を付けることができますが、Goでは常に名前を付けます。 ok:

count, ok := counts["sammy"]

キーの場合 sammy に存在します counts マップ、次に ok になります true. さもないと ok falseになります。

あなたは使用することができます ok プログラムで何をするかを決定する変数:

if ok {
	fmt.Printf("Sammy has a count of %d\n", count)
} else {
	fmt.Println("Sammy was not found")
}

これにより、次の出力が得られます。

Output
Sammy was not found

Goでは、変数宣言と条件付きチェックをif/elseブロックと組み合わせることができます。 これにより、このチェックに1つのステートメントを使用できます。

if count, ok := counts["sammy"]; ok {
	fmt.Printf("Sammy has a count of %d\n", count)
} else {
	fmt.Println("Sammy was not found")
}

Goでマップから値を取得するときは、プログラムのバグを回避するために、その存在も確認することをお勧めします。

マップの変更

マップは変更可能なデータ構造であるため、変更することができます。 このセクションでマップアイテムの追加と削除を見てみましょう。

マップアイテムの追加と変更

メソッドや関数を使用せずに、キーと値のペアをマップに追加できます。 これを行うには、マップ変数名に続けて角かっこで囲まれたキー値を使用します [ ]、および等しいを使用して = 新しい値を設定する演算子:

map[key] = value

実際には、キーと値のペアを次のマップに追加することで、この作業を確認できます。 usernames:

usernames := map[string]string{"Sammy": "sammy-shark", "Jamie": "mantisshrimp54"}

usernames["Drew"] = "squidly"
fmt.Println(usernames)

出力には新しいものが表示されます Drew:squidly マップ内のキーと値のペア:

Output
map[Drew:squidly Jamie:mantisshrimp54 Sammy:sammy-shark]

マップは順序付けられていない状態で返されるため、このペアはマップ出力のどこにでも発生する可能性があります。 を使用する場合 usernames プログラムファイルの後半でマップすると、追加のキーと値のペアが含まれます。

この構文を使用して、キーに割り当てられた値を変更することもできます。 この場合、既存のキーを参照し、それに別の値を渡します。

と呼ばれる地図を考えてみましょう followers 特定のネットワーク上のユーザーのフォロワーを追跡します。 ユーザー "drew" 今日はフォロワーが急増したため、に渡された整数値を更新する必要があります "drew" 鍵。 を使用します Println() マップが変更されたことを確認する関数:

followers := map[string]int{"drew": 305, "mary": 428, "cindy": 918}
followers["drew"] = 342
fmt.Println(followers)

出力には、の更新された値が表示されます drew:

Output
map[cindy:918 drew:342 mary:428]

フォロワーの数がの整数値からジャンプしたことがわかります 305342.

この方法を使用して、ユーザー入力を使用してキーと値のペアをマップに追加できます。 と呼ばれる簡単なプログラムを書いてみましょう usernames.go これはコマンドラインで実行され、ユーザーからの入力で名前と関連するユーザー名を追加できます。

usernames.go
package main

import (
	"fmt"
	"strings"
)

func main() {
	usernames := map[string]string{"Sammy": "sammy-shark", "Jamie": "mantisshrimp54"}

	for {
		fmt.Println("Enter a name:")

		var name string
		_, err := fmt.Scanln(&name)

		if err != nil {
			panic(err)
		}

		name = strings.TrimSpace(name)

		if u, ok := usernames[name]; ok {
			fmt.Printf("%q is the username of %q\n", u, name)
			continue
		}

		fmt.Printf("I don't have %v's username, what is it?\n", name)

		var username string
		_, err = fmt.Scanln(&username)

		if err != nil {
			panic(err)
		}

		username = strings.TrimSpace(username)

		usernames[name] = username

		fmt.Println("Data updated.")
	}
}

usernames.go 最初に元のマップを定義します。 次に、名前を反復処理するためのループを設定します。 ユーザーに名前を入力し、それを格納する変数を宣言するように要求します。 次に、エラーが発生したかどうかを確認します。 その場合、プログラムはパニックで終了します。 なぜなら Scanln キャリッジリターンを含む入力全体をキャプチャします。入力からスペースを削除する必要があります。 あなたはこれを strings.TrimSpace 関数。

The if ブロックは、名前がマップに存在するかどうかをチェックし、フィードバックを出力します。 名前が存在する場合は、ループの先頭に戻ります。 名前がマップにない場合は、ユーザーにフィードバックを提供し、関連付けられた名前の新しいユーザー名を要求します。 プログラムは、エラーがあるかどうかを再度確認します。 エラーなしで、キャリッジリターンを削除し、ユーザー名の値を名前キーに割り当ててから、データが更新されたというフィードバックを出力します。

コマンドラインでプログラムを実行してみましょう。

  1. go run usernames.go

次の出力が表示されます。

Output
Enter a name: Sammy "sammy-shark" is the username of "Sammy" Enter a name: Jesse I don't have Jesse's username, what is it? JOctopus Data updated. Enter a name:

テストが終了したら、を押します CTRL + C プログラムをエスケープします。

これは、マップをインタラクティブに変更する方法を示しています。 この特定のプログラムでは、プログラムを終了するとすぐに CTRL + C ファイルの読み取りと書き込みを処理する方法を実装しない限り、すべてのデータが失われます。

要約すると、マップにアイテムを追加したり、値を変更したりできます。 map[key] = value 構文。

マップアイテムの削除

マップデータ型内でキーと値のペアを追加したり値を変更したりできるのと同様に、マップ内のアイテムを削除することもできます。

マップからキーと値のペアを削除するには、組み込み関数を使用できます delete(). 最初の引数は、削除するマップです。 2番目の引数は、削除するキーです。

delete(map, key)

権限のマップを定義しましょう:

permissions := map[int]string{1: "read", 2: "write", 4: "delete", 8: "create", 16:"modify"}

もう必要ありません modify 許可があるので、マップから削除します。 次に、地図を印刷して、削除されたことを確認します。

permissions := map[int]string{1: "read", 2: "write", 4: "delete", 8: "create", 16: "modify"}
delete(permissions, 16)
fmt.Println(permissions)

出力は削除を確認します:

Output
map[1:read 2:write 4:delete 8:create]

この線 delete(permissions, 16) キーと値のペアを削除します 16:"modify" から permissions 地図。

すべての値のマップをクリアしたい場合は、同じタイプの空のマップと等しくなるように設定することでクリアできます。 これにより、使用する新しい空のマップが作成され、古いマップはガベージコレクターによってメモリからクリアされます。

内のすべてのアイテムを削除しましょう permissions 地図:

permissions = map[int]string{}
fmt.Println(permissions)

出力は、キーと値のペアがない空のマップがあることを示しています。

Output
map[]

マップは変更可能なデータ型であるため、マップを追加、変更したり、アイテムを削除およびクリアしたりできます。

結論

このチュートリアルでは、Goの地図データ構造について説明しました。 マップはキーと値のペアで構成されており、インデックスに依存せずにデータを保存する方法を提供します。 これにより、他のデータ型との意味や関係に基づいて値を取得できます。

モバイルバージョンを終了