Maps

7 min read

Authors
banner

So, Go provides a built-in map type, and we'll learn how to use it.

But, the question is what are maps? And why do we need them?

maps

Well, A map is an unordered collection of key-value pairs. It maps keys to values. The keys are unique within a map while the values may not be.

It is used for fast lookups, retrieval, and deletion of data based on keys. It is one of the most used data structures.

Declaration

Let's start with the declaration

A map is declared using the following syntax

var m map[K]V

Where K is the key type and V is the value type

For example, here's how we can declare a map of string keys to int values

func main() {
	var m map[string]int

	fmt.Println(m)
}
$ go run main.go
nil

As we can see, the zero value of a map is nil.

A nilmap has no keys. Moreover, any attempt to add keys to a nilmap will result in a runtime error.

Initialization

There are multiple ways to initialize a map.

make function

We can use the built-in make function, which allocates memory for referenced data types and initializes their underlying data structures.

func main() {
	var m = make(map[string]int)

	fmt.Println(m)
}
$ go run main.go
map[]

map literal

Another way is using map literal.

func main() {
	var m = map[string]int{
		"a": 0,
    "b": 1,
	}

	fmt.Println(m)
}

Note that the last trailing comma is necessary

$ go run main.go
map[a:0 b:1]

As always, we can use our custom types as well

type User struct {
	Name string
}

func main() {
	var m = map[string]User{
		"a": User{"Peter"},
		"b": User{"Seth"},
	}

	fmt.Println(m)
}

We can even remove the value type and Go will figure it out!

var m = map[string]User{
	"a": {"Peter"},
	"b": {"Seth"},
}
$ go run main.go
map[a:{Peter} b:{Seth}]

Add

Now, let's see how we can add a value to our map.

func main() {
	var m = map[string]User{
		"a": {"Peter"},
		"b": {"Seth"},
	}

	m["c"] = User{"Steve"}

	fmt.Println(m)
}
$ go run main.go
map[a:{Peter} b:{Seth} c:{Steve}]

Retrieve

We can also retrieve our values from the map using the key

...
c := m["c"]
fmt.Println("Key c:", c)
$ go run main.go
key c: {Steve}

What if we use a key that is not present in the map?

...
d := m["d"]
fmt.Println("Key d:", d)

Yes, you guessed it! we will get the zero value of the map's value type.

$ go run main.go
Key c: {Steve}
Key d: {}

Exists

When you retrieve the value assigned to a given key, it returns an additional boolean value as well. The boolean variable will be true if the key exists, and false otherwise.

Let's try this in an example

...
c, ok := m["c"]
fmt.Println("Key c:", c, ok)

d, ok := m["d"]
fmt.Println("Key d:", d, ok)
$ go run main.go
Key c: {Steve} Present: true
Key d: {} Present: false

Updating

We can also update the value for a key by simply re-assigning a key

...
m["a"] = "Roger"
$ go run main.go
map[a:{Roger} b:{Seth} c:{Steve}]

Deleting

Or, we can delete the key using the built-in delete function.

Here's how the syntax looks

...
delete(m,

The first argument is the map, and the second is the key we want to delete.

The delete() function doesn't return any value. Also, it doesn't do anything if the key doesn't exist in the map.

$ go run main.go
map[a:{Roger} c:{Steve}]

Iteration

Similar to arrays or slices, we can iterate over maps with the range keyword

package main

import "fmt"

func main() {
	var m = map[string]User{
		"a": {"Peter"},
		"b": {"Seth"},
	}

	m["c"] = User{"Steve"}

	for key, value := range m {
		fmt.Println("Key: %s, Value: %v", key, value)
	}
}
$ go run main.go
Key: c, Value: {Steve}
Key: a, Value: {Peter}
Key: b, Value: {Seth}

Note that a map is an unordered collection, and therefore the iteration order of a map is not guaranteed to be the same every time we iterate over it.

Properties

Lastly, let's talk about map properties.

Maps are reference types, which means when we assign a map to a new variable, they both refer to the same underlying data structure.

Therefore, changes done by one variable will be visible to the other.

package main

import "fmt"

type User struct {
	Name string
}

func main() {
	var m1 = map[string]User{
		"a": {"Peter"},
		"b": {"Seth"},
	}

	m2 := m1
	m2["c"] = User{"Steve"}

	fmt.Println(m1) // Output: map[a:{Peter} b:{Seth} c:{Steve}]
	fmt.Println(m2) // Output: map[a:{Peter} b:{Seth} c:{Steve}]
}

Well, this wraps up our discussion on maps, see you in the next tutorial!

© 2022 Shiva Poudel