DEV Community

Frihk Ian
Frihk Ian

Posted on

Maps in Golang

Maps are one of the most flexible data types in Go. It might even be the most flexible compared to maps from other programming languages. And just as flexible as they are , they are also as simple to initialize.

Understanding Map Structure
A map in Go is composed of two main parts: the key and the value. The key is defined as a unique label used to store and find a specific
Maps are one of the main data structures in Go. Maps have two main parts : the key and the value. The key is like a word you are looking up in a dictionary. It is a unique label that stores and carries a specific type of data. Whilst the value is like the definition of the word you are looking up in a dictionary, it is the data that is stored in the key value. Unlike keys, which only accept comparable types, the value can be of any legal Go type.

In Go, there are two main ways to initialize maps. The first uses the Go built-in make function:

m := make(map[string]int)

The second one uses a map literal:

m := map[string]int{}

They initialize an empty map that takes in a string as the key and an integer as the value. The make method is more flexible because it allows you to specify an initial capacity. When the expected size is known, this preallocation can reduce map growth and rehashing during execution.

Accessing Values and Handling Missing Keys
Reading from a map in Go is quite simple. You access a value by indexing the map with its key, as shown below:
age := m["John"]
Sometimes you might call a key that is not in the map; this happens as a result of misspelling or during testing. Go does not display any error, nor does it crash. It instead displays the zero value of the map's value type.

package main

import "fmt"

func main() {
    m := make(map[string]int)
    value := m["missing_key"] // value is 0
    fmt.Print(value)
}
Enter fullscreen mode Exit fullscreen mode

The program above displays:

0

The “Comma ok” Idiom
This can be misleading; if a key has a value of zero, it becomes difficult to know whether the key has a zero value or its value is a zero. Go handles this by introducing the “ok” to help solve this error. This helps distinguish the erroneous value and the correct value.

value, ok := m["missing_key"]
if !ok {
Return “Error” // The key does not exist in the map
}

Here, the value is the data in the map value. Whilst the “ok” is a boolean that is true. If the value exist then the ok becomes true, and the program executes without any error. If it does not exist, then the program returns an “error.”

Inserting and Updating Data
In Go, the syntax for inserting, updating, or deleting data in a map is consistent and straightforward. When adding/ updating a key, you simply assign a value; the method is pretty much the same as shown below.

m := make(map[string]int)

// Insert: Key "Alice" does not exist, so it is created.
m["Alice"] = 25 

// Update: Key "Alice" already exists, so its value is overwritten.
m["Alice"] = 26 
Enter fullscreen mode Exit fullscreen mode

Deleting Elements
When deleting from a map, we use the Go built-in function delete(). It removes the key and everything associated with it. Below is its syntax:

m := map[string]int{"Alice": 25, "Bob": 30}

// Removes "Alice" from the map
delete(m, "Alice")
Enter fullscreen mode Exit fullscreen mode

The delete function has a safety feature that makes it very safe to work with. In case of deletion of something that is not in the map, it simply does nothing.

Iterating Over Maps
Now that you know how to add and remove individual items, you’ll likely want to loop through the entire collection. In Go, we use the range keyword to iterate over a map.

m := map[string]int{Alice: 25, Bob: 30, Charlie: 35}

for key, value := range m {
fmt.Printf(Key: %s, Value: %d\n, key, value)
}
Enter fullscreen mode Exit fullscreen mode

Something to keep in mind when it comes to maps is that they are “commitment-phobic” when it comes to order. Unlike arrays or slices, they do not have a specified order during iteration. If you run the code above three times, chances are that you might get three different sequences. If you need a consistent order, you’ll have to sort the keys manually in a separate slice first.

Maps as Reference Types
The most significant points to keep in mind are that maps are a type of reference. Passing a map to a function does not give a copy of the data, but the pointer to the underlying data structure.
This implies that when you make changes to a map within a function, the changes will be carried over to the original map.

func updateAge(m map[string]int) {
m[Alice] = 30 // This changes the original map!
}
Enter fullscreen mode Exit fullscreen mode

Map Performance and Concurrency
Maps are incredibly fast, offering O(1) average time complexity for searches, additions, and deletions. Maps are extremely quick with an average time complexity of O(1) for searches, add, and delete. There is, however, a kind of safety limit that they have: Maps are not thread-safe.
If two different goroutines try to write to the same map at the same time, your program will crash with a fatal error: concurrent map writes

Feature 
Behavior in Golang Maps
Search Speed
Extremely fast (Constant time)
Iteration Order
Random/Unordered
Thread Safety
None (Requires sync.Mutex or sync.Map)
Zero Value
nil (A nil map can be read, but writing to it causes a panic)
Enter fullscreen mode Exit fullscreen mode

Conclusion
Maps are the go-to tool in Go when you need a fast, associative data structure. By mastering the make function, the “comma ok” idiom, and understanding the nuances of iteration and reference types, you can handle complex data relationships with very little code.

Top comments (0)