Go Maps Made Simple
In Go, maps are used to store data in key-value pairs. That means each piece of data has a unique key that points to a value.
What You Need to Know About Maps:
- A map holds key:value pairs. For example:{"name": "Alice", "age": 25}
- Here, "name" and "age" are keys, and "Alice" and 25 are their values.
- Maps are unordered, which means the data inside doesn’t follow a fixed order.
- You can change a map by adding, updating, or deleting items.
- Duplicate keys are not allowed. If you add the same key again, the old value will be replaced.
- You can find out how many items are in a map using the len() function.
- If a map hasn’t been created yet, its default value is nil. A nil map doesn’t work until you initialize it.
- Maps in Go use an underlying hash table to store data efficiently.
- There are different ways to create maps in Go, such as using a map literal or the make() function.
Example:
// Creating a map with some values
person := map[string]string{
"name": "John",
"city": "New York",
}
// Getting the number of items in the map
fmt.Println(len(person)) // Output: 2
Creating Maps in Go Using var and :=
In Go, you can create maps in two main ways:
1. Using var
You can declare a map with the var keyword and assign key-value pairs.
var a = map[KeyType]ValueType{
key1: value1,
key2: value2,
}
2. Using := (Short Variable Declaration)
This is a shorter way to create and assign a map at the same time.
b := map[KeyType]ValueType{
key1: value1,
key2: value2,
}
Example: Creating Maps
Here's a full Go program that creates two maps — one using var, the other using :=:
package main
import "fmt"
func main() {
var a = map[string]string{
"brand": "Ford",
"model": "Mustang",
"year": "1964",
}
b := map[string]int{
"Oslo": 1,
"Bergen": 2,
"Trondheim": 3,
"Stavanger": 4,
}
fmt.Printf("a\t%v\n", a)
fmt.Printf("b\t%v\n", b)
}
Output:
a map[brand:Ford model:Mustang year:1964]
b map[Bergen:2 Oslo:1 Stavanger:4 Trondheim:3]
Creating Maps With make()
The built‑in make function allocates and returns an empty map that you can populate later.
// Long form
var m = make(map[KeyType]ValueType)
// Short form (idiomatic in Go)
n := make(map[KeyType]ValueType)
Example:
Below, we build two maps at runtime—one that holds car details and another that assigns IDs to Norwegian cities.
package main
import "fmt"
func main() {
// Map for car information
cars := make(map[string]string)
cars["brand"] = "Ford"
cars["model"] = "Mustang"
cars["year"] = "1964"
// Map for city IDs
cities := make(map[string]int)
cities["Oslo"] = 1
cities["Bergen"] = 2
cities["Trondheim"] = 3
cities["Stavanger"] = 4
fmt.Printf("cars:\t%v\n", cars)
fmt.Printf("cities:\t%v\n", cities)
}
Output:
cars: map[brand:Ford model:Mustang year:1964]
cities: map[Bergen:2 Oslo:1 Stavanger:4 Trondheim:3]
Declaring an Empty Map in Go
You have two ways to end up with an “empty” map:
Rule of thumb: Use make unless you truly want a nil map for some special purpose (e.g., to signal “no data”).
Example
package main
import "fmt"
func main() {
a := make(map[string]string) // empty but non‑nil
var b map[string]string // nil map
fmt.Println(a == nil) // false — ready to use
fmt.Println(b == nil) // true — nil, will panic if written to
}
Output
false
true
Because a was created with make, it’s a valid map and can be populated right away. b, on the other hand, is nil; writing to it (b["key"] = "value") would trigger a panic at runtime.
Allowed Key Types in Maps
In Go, map keys must be of a type that supports the equality operator (==). Valid key types include:
- Booleans
- Numbers
- Strings
- Arrays
- Pointers
- Structs
- Interfaces (only if the underlying dynamic type supports equality)
Invalid Key Types
The following types cannot be used as map keys because they do not support the equality operator:
- Slices
- Maps
- Functions
Permissible Value Types
A map’s values can be any Go type—primitive or user‑defined.
Reading Data from a Map
To look up a value, put the desired key in square brackets after the map variable:
value := myMap[key]
Example:
package main
import "fmt"
func main() {
car := make(map[string]string) // create an empty map
// populate the map
car["brand"] = "Ford"
car["model"] = "Mustang"
car["year"] = "1964"
// retrieve and print a value
fmt.Println(car["brand"]) // Output: Ford
}
Output:
Ford
Adding or Updating Entries in a Map
You insert a new key–value pair, or change an existing one, with the assignment syntax:
mapVar[key] = value
Example:
package main
import "fmt"
func main() {
car := make(map[string]string) // create an empty map
// initial data
car["brand"] = "Ford"
car["model"] = "Mustang"
car["year"] = "1964"
fmt.Println(car) // map[brand:Ford model:Mustang year:1964]
// modify an existing entry
car["year"] = "1970"
// add a brand‑new entry
car["color"] = "red"
fmt.Println(car) // map[brand:Ford color:red model:Mustang year:1970]
}
The first fmt.Println shows the map’s original state, while the second confirms that year was updated and color was added.
Removing Elements from a Map
To remove an element from a map, use the built-in delete() function:
delete(mapVar, key)
Example
package main
import "fmt"
func main() {
car := make(map[string]string)
car["brand"] = "Ford"
car["model"] = "Mustang"
car["year"] = "1964"
fmt.Println(car) // map[brand:Ford model:Mustang year:1964]
delete(car, "year") // remove the "year" key
fmt.Println(car) // map[brand:Ford model:Mustang]
}
Checking If a Key Exists in a Map
To determine whether a key exists in a map, use this syntax:
value, exists := mapVar[key]
If you only care about whether the key exists (not the value), use the blank identifier _:
_, exists := mapVar[key]
Example
package main
import "fmt"
func main() {
car := map[string]string{
"brand": "Ford",
"model": "Mustang",
"year": "1964",
"day": "",
}
val1, ok1 := car["brand"] // key exists, value is "Ford"
val2, ok2 := car["color"] // key does not exist
val3, ok3 := car["day"] // key exists, value is an empty string
_, ok4 := car["model"] // check existence only
fmt.Println(val1, ok1) // Ford true
fmt.Println(val2, ok2) // false
fmt.Println(val3, ok3) // true
fmt.Println(ok4) // true
}
This output confirms:
- "brand" exists and has a value
- "color" does not exist
- "day" exists but has an empty string as its value
- "model" exists (checked without retrieving the value)
Maps Are Reference Types
A map variable holds a reference to an underlying hash table.
If two map variables point to the same table, modifying either one changes the shared data:
package main
import "fmt"
func main() {
car := map[string]string{
"brand": "Ford",
"model": "Mustang",
"year": "1964",
}
copyRef := car // copyRef and car reference the same map
fmt.Println(car) // map[brand:Ford model:Mustang year:1964]
fmt.Println(copyRef) // map[brand:Ford model:Mustang year:1964]
copyRef["year"] = "1970" // update through copyRef
fmt.Println("After change:")
fmt.Println(car) // map[brand:Ford model:Mustang year:1970]
fmt.Println(copyRef) // map[brand:Ford model:Mustang year:1970]
}
Iterating Over a Map
Use range to loop through key–value pairs. Remember that the iteration order is not guaranteed:
package main
import "fmt"
func main() {
nums := map[string]int{
"one": 1,
"two": 2,
"three": 3,
"four": 4,
}
for k, v := range nums {
fmt.Printf("%s : %d, ", k, v)
}
// Example output (order will vary):
// two : 2, three : 3, four : 4, one : 1,
}
Iterating Over a Map in a Defined Order
Because Go maps are inherently unordered, you must keep a separate slice that lists the keys in the order you want. Then iterate over that slice to access the map’s values in sequence.
package main
import "fmt"
func main() {
// the map itself (unordered)
numbers := map[string]int{
"one": 1,
"two": 2,
"three": 3,
"four": 4,
}
// desired iteration order
order := []string{"one", "two", "three", "four"}
//– Unordered iteration (order will vary each run)
for k, v := range numbers {
fmt.Printf("%s : %d, ", k, v)
}
fmt.Println()
//– Ordered iteration using the key slice
for _, key := range order {
fmt.Printf("%s : %d, ", key, numbers[key])
}
}
Typical output:
two : 2, three : 3, four : 4, one : 1,
one : 1, two : 2, three : 3, four : 4,
The first loop reflects the map’s unpredictable ordering, while the second loop follows the explicit sequence defined in order.