In Go language, map is a very practical data structure that provides storage and query functions for keyvalue pairs, similar to dictionaries, hash tab...
An in-depth look at maps in Go
Published: 2025-07-24 (a year ago)
GO

In Go language, map is a very practical data structure that provides storage and query functions for key-value pairs, similar to dictionaries, hash tables, etc. in other programming languages. Map is widely used in practical development due to its efficient finding, inserting, and deletion operations. This article will introduce the relevant knowledge of map in Go language in detail, including its definition, characteristics, basic operations, traversal, deletion, sorting, and concurrency security.

Basic definition and characteristics of map

map is an unordered collection of key-value pairs, where the key must be of a comparable type, which means that the '==' and '!=' operators can be used to determine the position of the key in the map. Common types that can be used as keys are int, string, bool, pointer, struct (when the fields in the struct are all comparable types), etc. The value can be of any type, including basic type, compound type, or even function type.

An important feature of map is that it is a reference type. This means that when we assign a map to another variable, they point to the same underlying data structure, and modifying the map to which one variable points will affect the other variable. For example:

Copy
package main

import "fmt"

func main() {

m1 := map\[string]int{"a": 1, "b": 2}

m2 := m1

m2\["a"] = 100

fmt. Println(m1) // Output: map\[a:100 b:2]

}

In the above code, m2 is a copy of m1, but they point to the same map, so if you modify the value of "a" in m2, the value of "a" in m1 will also change.

In addition, maps can grow and contract dynamically after creation, without the need to specify a fixed size in advance, which brings a lot of flexibility to development.

Map creation and initialization

In Go, there are two common ways to create a map: using the 'make' function and using map literals.

Create a map using the make function

The 'make' function is used to create a map and can optionally specify the initial capacity of the map. Its basic syntax is as follows:

Copy
map variable name := make(map\[key type] value type, \[initial capacity])

The initial capacity is an optional parameter that specifies the amount of storage space that the map pre-allocates when it is created. Specifying an appropriate initial capacity can reduce the scale operation of the map during use and improve performance. For example:

Copy
Create a map with a key of type string and a value of type int, with an initial capacity of 10

m := make(map\[string]int, 10)

Create a map with map literals

map literals allow us to initialize the map at the same time as it is created, giving it an initial key-value pair. The syntax is as follows:

Copy
map variable name := map\[key type] value type {

Key 1: Value 1,

Key 2: Value 2,

// ...

}

For example:

Copy
Create and initialize a map

m := map\[string]string{

    "name": "Zhang San",

"age":  "20",

    "city": "Beijing",

}

If you create an empty map, you can also use the following:

Copy
m := map\[string]int{}

Basic operations of map

The basic operations of a map include inserting, querying, and modifying elements, all of which are very simple and intuitive.

Insert elements

The syntax for inserting elements into a map is:

Copy
map variable name \[key] = value

For example, insert an element into a map from a string to int:

Copy
m := make(map\[string]int)

m\["apple"] = 5

m\["banana"] = 3

Query elements

When querying an element from a map, you can use the following syntax:

Copy
value, ok := map variable name \[key]

Here 'ok' is a bool type value, if the key exists in the map, 'ok' is 'true' and 'value' is the corresponding value; if the key does not exist, 'ok' is 'false' and 'value' is the zero value of the value type. This query method is very convenient to determine whether the key exists in the map. For example:

Copy
m := map\[string]int{"apple": 5, "banana": 3}

count, ok := m\["apple"]

if ok {

fmt. Println("The number of apples is:", count) // Output: The number of apples is: 5

} else {

fmt. Println ("Apple does not exist in map")

}

Query for keys that do not exist

count, ok = m\["orange"]

if ok {

fmt. Println("The number of oranges is:", count)

} else {

fmt. Println("orange does not exist in map") // Output: orange does not exist in map

}

If you only care about the value and not whether the key exists, you can also directly use 'value:= map variable name [key]', but in this case, if the key does not exist, it will return the zero value of the value type, which may lead to some misunderstandings, so in actual development, it is recommended to use the query method with 'ok'.

Modify the element

Modifying the value of an existing key in the map is as simple as reassigning the key:

Copy
m := map\[string]int{"apple": 5, "banana": 3}

m\["apple"] = 10 // Modify the value of apple to 10

fmt. Println(m\["apple"]) // Output: 10

Traversal of map

In Go, you can use the 'for range' loop to traverse key-value pairs in a map. The 'for range' loop takes two common forms: one gets both the key and the value, and the other gets only the key.

Get both the key and the value

Copy
m := map\[string]int{"apple": 5, "banana": 3, "orange": 7}

for key, value := range m {

fmt. Printf("key: %s, value: %d\n", key, value)

}

It is important to note that map traversal is unordered, and the order of key-value pairs obtained from each traversal may be different. This is due to the underlying hash table implementation of map, which stores key-value pairs based on the hash value of the key, and the distribution of hash values is uncertain.

Get only the key

If you only need to traverse the keys in the map, you can use the following:

Copy
m := map\[string]int{"apple": 5, "banana": 3, "orange": 7}

for key := range m {

fmt. Println("key:", key)

}

Removal of map

To delete a key-value pair in a map, you can use the built-in 'delete' function, which has the following syntax:

Copy
delete(map variable name, key)

If the specified key does not exist, the 'delete' function does nothing and does not return an error. For example:

Copy
m := map\[string]int{"apple": 5, "banana": 3, "orange": 7}

delete(m, "banana") // The key to delete is the key-value pair of banana

fmt. Println(m) // Output:map\[apple:5 orange:7]

delete(m, "grape") // Delete non-existent keys without any action

Sorting of maps

Since map traversal is unordered, in some scenarios, we may need to handle key-value pairs in the map in a certain order (such as ascending and descending keys). In this case, we can first extract the keys in the map into a slice, sort the slices, and then traverse the map based on the sorted slices.

For example, traversing the map in ascending order of the keys:

Copy
package main

import (

    "fmt"

"sort"

)

func main() {

m := map\[string]int{"apple": 5, "banana": 3, "orange": 7, "pear": 2}

    

Extract the key from the map into the slice

keys := make(\[]string, 0, len(m))

for key := range m {

keys = append(keys, key)

    }

    

Sort slices (ascending)

sort. Strings(keys)

    

Follow the sorted key to traverse the map

for \_, key := range keys {

fmt. Printf("key: %s, value: %d\n", key, m\[key])

    }

}

Run the above code and the output is as follows (keys in ascending alphabetical order):

Copy
key: apple, value: 5

key: banana, value: 3

key: orange, value: 7

key: pear, value: 2

If you need to sort in descending order, you can invert the slices after sorting, or use a custom sort function.

Concurrency security for maps

It is important to note that maps in Go are not concurrency-safe. In other words, when multiple goroutines read and write to a map at the same time, it may cause program crashes or data inconsistency. For example:

Copy
package main

import (

    "fmt"

"sync"

)

func main() {

m := make(map\[int]int)

var wg sync. WaitGroup

    

Start 10 goroutines to write data to the map at the same time

for i := 0; i < 10; i++ {

wg. Add(1)

go func(num int) {

defer wg. Done()

m\[num] = num

}(i)

    }

    

wg. Wait()

fmt. Println(m)

}

Running the above code, you will most likely get the error 'fatal error: concurrent map writes', which is caused by multiple goroutines writing to the map at the same time.

To solve the concurrency security problem of maps, we can use 'sync. Map' (introduced in Go 1.9 and above), or use mutex ('sync. Mutex') or read/write locks ('sync. RWMutex') to secure access to the map.

Use sync Map

`sync. Map is a concurrency-safe map implementation provided in the Go language standard library, which provides methods such as Store (store key-value pairs), 'Load' (get the value corresponding to the key), 'Delete' (delete the key-value pair), 'Range' (traverse the key-value pair) and so on. For example:

Copy
package main

import (

    "fmt"

"sync"

)

func main() {

var m sync. Map

var wg sync. WaitGroup

    

Start 10 goroutines and write data to sync. Map at the same time

for i := 0; i < 10; i++ {

wg. Add(1)

go func(num int) {

defer wg. Done()

m.Store(num, num)

}(i)

    }

    

wg. Wait()

    

Traversing sync Map

m.Range(func(key, value interface{}) bool {

fmt. Printf("key: %d, value: %d\n", key, value)

return true

    })

}

Use mutexes

We can also use 'sync. Mutex' to ensure the mutually exclusive nature of map operations, i.e. only one goroutine is allowed to operate on the map at a time. For example:

Copy
package main

import (

    "fmt"

"sync"

)

func main() {

m := make(map\[int]int)

var mu sync. Mutex

var wg sync. WaitGroup

    

Start 10 goroutines to write data to the map at the same time

for i := 0; i < 10; i++ {

wg. Add(1)

go func(num int) {

defer wg. Done()

mu. lock() // Add a lock

m\[num] = num

mu. Unlock() // Unlock

}(i)

    }

    

wg. Wait()

fmt. Println(m)

}

If there are far more reads than writes, using sync. RWMutex can improve performance because sync. RWMutex allows multiple goroutines to perform reads at the same time, but writes are mutually exclusive and writes block reads.

Summary

As an important data structure in the Go language, map provides us with convenient key-value pair storage and operation methods. This article introduces in detail the definition, characteristics, creation and initialization of map, basic operations (insert, query, modification), traversal, deletion, sorting, and concurrency security.

When using map, we need to pay attention to key comparability, map is a reference type, traversal disorder, and concurrency security issues. Reasonable use of map can improve the efficiency and readability of the program, and understanding the underlying implementation and characteristics of map can help us use it better and avoid unnecessary errors in development.

I hope that through the introduction of this article, readers can deeply understand maps in Go language and use them flexibly in actual development.

(Note: Some parts of the document may be AI-generated)