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 nil map has no keys. Moreover, any attempt to add keys to a nil map 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 a map literal.

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

	fmt.Println(m)
}

Note that the trailing comma is required.

$ 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

Update

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}]

Delete

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

Here's how the syntax looks:

...
delete(m, "a")

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}]
}
© 2024 Karan Pratap Singh