最新のプログラミング言語のほとんどには、dictionaryまたはhashタイプの概念があります。 これらのタイプは通常、valueにマップされるkeyとペアでデータを格納するために使用されます。
Goでは、mapデータ型は、ほとんどのプログラマーがdictionary型と考えるものです。 キーに値をマッピングして、Goにデータを保存する便利な方法であるキーと値のペアを作成します。 マップは、キーワードmap
、角括弧[ ]
内のキーデータ型、値データ型を使用して作成されます。 次に、キーと値のペアは、どちらかの側の波括弧の中に配置されます\ {}:
map[key]value{}
通常、Goでマップを使用して、IDに含まれる情報などの関連データを保持します。 データを含むマップは次のようになります。
map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
中括弧に加えて、キーと値のペアを接続するコロンがマップ全体にあります。 コロンの左側の単語がキーです。 キーは、strings
、ints
など、Goの任意のcomparableタイプにすることができます。
サンプルマップのキーは次のとおりです。
-
"name"
-
"animal"
-
"color"
-
"location"
コロンの右側の単語は値です。 値は任意のデータ型にすることができます。 サンプルマップの値は次のとおりです。
-
"Sammy"
-
"shark"
-
"blue"
-
"ocean"
他のデータ型と同様に、マップを変数内に保存し、印刷することができます。
sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
fmt.Println(sammy)
これはあなたの出力になります:
Outputmap[animal:shark color:blue location:ocean name:Sammy]
キーと値のペアの順序がずれている可能性があります。 Goでは、マップのデータ型は順不同です。 順序に関係なく、キーと値のペアはそのまま残り、関係の意味に基づいてデータにアクセスできます。
マップアイテムへのアクセス
関連するキーを参照することにより、マップの値を呼び出すことができます。 マップはデータを格納するためのキーと値のペアを提供するため、Goプログラムで重要かつ有用なアイテムになる可能性があります。
サミーのユーザー名を分離したい場合は、sammy["name"]
を呼び出すことで分離できます。マップと関連キーを保持する変数。 それを印刷してみましょう:
fmt.Println(sammy["name"])
出力として値を受け取ります。
OutputSammy
マップはデータベースのように動作します。スライスの場合のように整数を呼び出して特定のインデックス値を取得する代わりに、キーに値を割り当て、そのキーを呼び出して関連する値を取得します。
キー"name"
を呼び出すと、そのキーの値である"Sammy"
を受け取ります。
同様に、同じ形式を使用して、sammy
マップの残りの値を呼び出すことができます。
fmt.Println(sammy["animal"])
// returns shark
fmt.Println(sammy["color"])
// returns blue
fmt.Println(sammy["location"])
// returns ocean
マップデータタイプでキーと値のペアを使用することにより、キーを参照して値を取得できます。
キーと値
一部のプログラミング言語とは異なり、Goには、マップのキーまたは値を一覧表示するためのconvenience関数がありません。 この例は、辞書用の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
も文字列になります。 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
パッケージのsort.Strings
関数を使用します。
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))
出力には、マップ内のアイテムの数が表示されます。
Output4
Goにはキーと値を取得するための便利な関数が付属していませんが、必要なときにキーと値を取得するのに数行のコードしか必要ありません。
存在の確認
Goのマップは、要求されたキーが欠落している場合、マップの値タイプのゼロ値を返します。 このため、保存されたゼロと欠落キーを区別する代替方法が必要です。
存在しないことがわかっているマップで値を検索し、返される値を見てみましょう。
counts := map[string]int{}
fmt.Println(counts["sammy"])
次の出力が表示されます。
Output0
キーsammy
がマップになかったとしても、Goは0
の値を返しました。 これは、値のデータ型がint
であり、Goはすべての変数に対してゼロ値を持っているため、0
のゼロ値を返すためです。
多くの場合、これは望ましくなく、プログラムのバグにつながります。 マップで値を検索すると、Goは2番目のoptional値を返すことができます。 この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")
}
これにより、次の出力が得られます。
OutputSammy was not found
Goでは、変数宣言と条件チェックをif / elseブロックと組み合わせることができます。 これにより、このチェックに単一のステートメントを使用できます。
if count, ok := counts["sammy"]; ok {
fmt.Printf("Sammy has a count of %d\n", count)
} else {
fmt.Println("Sammy was not found")
}
Goでマップから値を取得するときは、プログラムのバグを回避するために、その存在も確認することを常にお勧めします。
マップの変更
マップは変更可能なデータ構造であるため、変更できます。 このセクションのマップアイテムの追加と削除を見てみましょう。
マップアイテムの追加と変更
メソッドまたは関数を使用せずに、キーと値のペアをマップに追加できます。 これを行うには、maps変数名に続けて角括弧[ ]
で囲まれたキー値を使用し、等しい=
演算子を使用して新しい値を設定します。
map[key] = value
実際には、usernames
という名前のマップにキーと値のペアを追加することでこの作業を確認できます。
usernames := map[string]string{"Sammy": "sammy-shark", "Jamie": "mantisshrimp54"}
usernames["Drew"] = "squidly"
fmt.Println(usernames)
出力には、マップ内の新しいDrew:squidly
のキーと値のペアが表示されます。
Outputmap[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
の更新された値が表示されます。
Outputmap[cindy:918 drew:342 mary:428]
フォロワーの数が305
の整数値から342
に急増したことがわかります。
このメソッドを使用して、キーと値のペアをユーザー入力付きのマップに追加できます。 コマンドラインで実行され、ユーザーからの入力で名前と関連するユーザー名を追加できる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
で、最初に元のマップを定義します。 次に、名前を反復処理するループを設定します。 ユーザーに名前を入力し、保存する変数を宣言するよう要求します。 次に、エラーが発生したかどうかを確認します。その場合、プログラムはpanicで終了します。 Scanln
はキャリッジリターンを含む入力全体をキャプチャするため、入力からスペースを削除する必要があります。これは、strings.TrimSpace
関数を使用して行います。
if
ブロックは、名前がマップに存在するかどうかを確認し、フィードバックを出力します。 名前が存在する場合、ループの先頭に戻ります。 名前がマップにない場合、ユーザーにフィードバックを提供し、関連する名前の新しいユーザー名を要求します。 プログラムは再度エラーがあるかどうかを確認します。 エラーなしで、キャリッジリターンが削除され、ユーザー名の値が名前キーに割り当てられ、データが更新されたというフィードバックが出力されます。
コマンドラインでプログラムを実行しましょう:
go run usernames.go
次の出力が表示されます。
OutputEnter 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)
出力は削除を確認します:
Outputmap[1:read 2:write 4:delete 8:create]
行delete(permissions, 16)
は、キーと値のペア16:"modify"
をpermissions
マップから削除します。
すべての値のマップをクリアする場合は、同じタイプの空のマップと同じ値に設定することにより、マップをクリアできます。 これにより、使用する新しい空のマップが作成され、古いマップはガベージコレクターによってメモリからクリアされます。
permissions
マップ内のすべてのアイテムを削除しましょう。
permissions = map[int]string{}
fmt.Println(permissions)
出力は、キーと値のペアがない空のマップがあることを示しています。
Outputmap[]
マップは変更可能なデータ型であるため、追加、変更、およびアイテムの削除とクリアが可能です。
結論
このチュートリアルでは、Goのマップデータ構造について説明しました。 マップはキーと値のペアで構成され、インデックス作成に依存せずにデータを保存する方法を提供します。 これにより、その意味と他のデータ型との関係に基づいて値を取得できます。