Golang Maps Tutorial
Welcome to tutorial no. 13 in Golang tutorial series.
What is a map?
A map is a inbuilt data type in Go which is used to store key-value pairs. A practical use case for a map is for storing the currency codes and the corresponding currency names.
USD - United States Dollar
EUR - Euro
INR - India Rupee
A map will be a perfect fit for the above use case use case. The currency code can be the key and the currency name can be the value. Maps are similar to dictionaries in other languages such as Python.
How to create a map?
A map can be created by passing the data type of key and value to the make
function. The following is the syntax to create a new map.
make(map[type of key]type of value)
currencyCode := make(map[string]string)
The above line of code creates a map named currencyCode
which has string
keys and string
values.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := make(map[string]string)
9 fmt.Println(currencyCode)
10}
The program above creates a map named currencyCode
with string
key and string
value. The above program will print,
map[]
Since we have not added any elements to the map, it’s empty.
Adding items to a map
The syntax for adding new items to a map is the same as that of arrays. The program below adds some new currency codes and currency names to the currencyCode
map.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := make(map[string]string)
9 currencyCode["USD"] = "US Dollar"
10 currencyCode["GBP"] = "Pound Sterling"
11 currencyCode["EUR"] = "Euro"
12 currencyCode["INR"] = "Indian Rupee"
13 fmt.Println("currencyCode map contents:", currencyCode)
14}
We have added 4 currencyCodes namely USD
, GBP
, EUR
, INR
and their corresponding names.
The above program prints,
currencyCode map contents: map[EUR:Euro GBP:Pound Sterling INR:Indian Rupee USD:US Dollar]
As you might have recognized from the above output, the order of the retrieval of values from a map is not guaranteed to be the same as the order in which the elements were added to the map.
It is also possible to initialize a map during the declaration itself.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := map[string]string {
9 "USD": "US Dollar",
10 "GBP": "Pound Sterling",
11 "EUR": "Euro",
12 }
13 currencyCode["INR"] = "Indian Rupee"
14 fmt.Println("currencyCode map contents:", currencyCode)
15}
The above program declares currencyCode
map and adds 3 items to it during the declaration itself. Later one more element with key INR
is added. The program prints
currencyCode map contents: map[EUR:Euro GBP:Pound Sterling INR:Indian Rupee USD:US Dollar]
It’s not necessary that only string types should be keys. All comparable types such as boolean, integer, float, complex, string, … can also be keys. Even user-defined types such as structs can be keys. If you would like to know more about comparable types, please visit https://go.dev/ref/spec#Comparison_operators
nil map panics
The zero value of a map is nil
. If you try to add elements to a nil
map, a run-time panic will occur. Hence the map has to be initialized before adding elements.
1package main
2
3func main() {
4 var currencyCode map[string]string
5 currencyCode["USD"] = "US Dollar"
6}
In the above program, currencyCode
is nil
and we are trying to add a new key to a nil
map. The program will panic with error
panic: assignment to entry in nil map
Retrieving value for a key from a map
Now that we have added some elements to the map, let’s learn how to retrieve them. map[key]
is the syntax to retrieve elements of a map.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := map[string]string{
9 "USD": "US Dollar",
10 "GBP": "Pound Sterling",
11 "EUR": "Euro",
12 }
13 currency := "USD"
14 currencyName := currencyCode[currency]
15 fmt.Println("Currency name for currency code", currency, "is", currencyName)
16}
The above program is pretty straightforward. The currency name for the currency code USD
is retrieved and printed. The program prints
Currency name for currency code USD is US Dollar
What will happen if an element is not present? The map will return the zero value of the type of that element. In the case of currencyCode
map, if we try to access an item which is not present, the zero value of string, “"(the empty string) is returned.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := map[string]string{
9 "USD": "US Dollar",
10 "GBP": "Pound Sterling",
11 "EUR": "Euro",
12 }
13 fmt.Println("Currency name for currency code INR is", currencyCode["INR"])
14}
The output of the above program is
Currency name for currency code INR is
The above program returns empty string as the currency name for INR
. There will be no runtime error when we try to retrieve the value for a key that is not present in the map.
Checking if a key exists
In the above section we learned that when a key is not present, the zero value of the type will be returned. This doesn’t help when we want to find out whether the key actually exists in the map.
For example, we want to know whether a currency code key is present in the currencyCode
map.
The following syntax is used to find out whether a particular key is present in a map.
value, ok := map[key]
ok
in the above line of code will be true
when the key is present and the value for the key is present in the variable value
.
If the key is not present, ok
will be false
and the zero value is returned for value
.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := map[string]string{
9 "USD": "US Dollar",
10 "GBP": "Pound Sterling",
11 "EUR": "Euro",
12 }
13 cyCode := "INR"
14 if currencyName, ok := currencyCode[cyCode]; ok {
15 fmt.Println("Currency name for currency code", cyCode, " is", currencyName)
16 return
17 }
18 fmt.Println("Currency name for currency code", cyCode, "not found")
19}
In the above program, in line no. 14, ok
will be false
since INR
key is not present. Hence the program will print,
Currency name for currency code INR not found
Iterate over all elements in a map
The range
form of the for
loop is used to iterate over all elements of a map.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := map[string]string{
9 "USD": "US Dollar",
10 "GBP": "Pound Sterling",
11 "EUR": "Euro",
12 }
13 for code, name := range currencyCode {
14 fmt.Printf("Currency Name for currency code %s is %s\n", code, name)
15 }
16}
The above program outputs,
Currency Name for currency code GBP is Pound Sterling
Currency Name for currency code EUR is Euro
Currency Name for currency code USD is US Dollar
One important fact to note is the order of the retrieval of values from a map when using for range
is not guaranteed to be the same for each execution of the program. It is also not the same as the order in which the elements were added to the map
Deleting items from a map
delete(map, key) is the syntax to delete key
from a map
. The delete function does not return any value.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := map[string]string{
9 "USD": "US Dollar",
10 "GBP": "Pound Sterling",
11 "EUR": "Euro",
12 }
13 fmt.Println("map before deletion", currencyCode)
14 delete(currencyCode, "EUR")
15 fmt.Println("map after deletion", currencyCode)
16}
The above program deletes the key EUR
and it prints
map before deletion map[EUR:Euro GBP:Pound Sterling USD:US Dollar]
map after deletion map[GBP:Pound Sterling USD:US Dollar]
Even if we try to delete a key that is not present in the map, there will be no runtime error.
Map of structs
So far we have only been storing the currency name in the map. Wouldn’t it be nice if we are able to store the symbol of the currency too? This can be achieved by using a map of structs. The currency can be represented as a struct containing the fields currency name and currency symbol. This struct value can be stored in the map with a currency code as key . Let’s write a program to understand how this can be done.
1package main
2
3import (
4 "fmt"
5)
6
7type currency struct {
8 name string
9 symbol string
10}
11
12func main() {
13 curUSD := currency{
14 name: "US Dollar",
15 symbol: "$",
16 }
17 curGBP := currency{
18 name: "Pound Sterling",
19 symbol: "£",
20 }
21 curEUR := currency{
22 name: "Euro",
23 symbol: "€",
24 }
25
26 currencyCode := map[string]currency{
27 "USD": curUSD,
28 "GBP": curGBP,
29 "EUR": curEUR,
30 }
31
32 for cyCode, cyInfo := range currencyCode {
33 fmt.Printf("Currency Code: %s, Name: %s, Symbol: %s\n", cyCode, cyInfo.name, cyInfo.symbol)
34 }
35
36}
In the above program, currency
struct contains fields name
and symbol
. We create three currencies curUSD
, curGBP
and curEUR
.
In line no. 26, we initialize a map with string
key and value of type currency
with the three currencies we created.
The map is iterated in line no. 32 and the currency details are printed in the next line. This program will print,
Currency Code: USD, Name: US Dollar, Symbol: $
Currency Code: GBP, Name: Pound Sterling, Symbol: £
Currency Code: EUR, Name: Euro, Symbol: €
Length of the map
Length of the map can be determined using the len function.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 currencyCode := map[string]string{
9 "USD": "US Dollar",
10 "GBP": "Pound Sterling",
11 "EUR": "Euro",
12 }
13 fmt.Println("length is", len(currencyCode))
14
15}
len(currencyCode) in the above program returns the length of the map. The above program prints,
length is 3
Maps are reference types
Similar to slices, maps are reference types. When a map is assigned to a new variable, they both point to the same underlying data structure. Hence changes made in one will reflect in the other.
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 employeeSalary := map[string]int{
9 "steve": 12000,
10 "jamie": 15000,
11 "mike": 9000,
12 }
13 fmt.Println("Original employee salary", employeeSalary)
14 modified := employeeSalary
15 modified["mike"] = 18000
16 fmt.Println("Employee salary changed", employeeSalary)
17
18}
In line no. 14 of the above program, employeeSalary
is assigned to modified
. In the next line, the salary of mike
is changed to 18000
in the modified
map. Mike’s salary will now be 18000
in employeeSalary
too. The program outputs,
Original employee salary map[jamie:15000 mike:9000 steve:12000]
Employee salary changed map[jamie:15000 mike:18000 steve:12000]
Similar is the case when maps are passed as parameters to functions. When any change is made to the map inside the function, it will be visible to the caller also.
Maps equality
Maps can’t be compared using the ==
operator. The ==
can be only used to check if a map is nil
.
1package main
2
3func main() {
4 map1 := map[string]int{
5 "one": 1,
6 "two": 2,
7 }
8
9 map2 := map1
10
11 if map1 == map2 {
12 }
13}
The above program will fail to compile with error
invalid operation: map1 == map2 (map can only be compared to nil)
One way to check whether two maps are equal is to compare each one’s individual elements one by one. The other way is using reflection. I would encourage you to write a program for this and make it work :).
This brings us to the end of this tutorial. Hope you enjoyed it. Please leave your feedback and comments. Please consider sharing this tutorial on twitter and LinkedIn. Have a good day.
Next tutorial - Strings