Introduction to Maps

A map is an unordered collection of key-value pairs. Each key is unique within a map, and the keys are used to look up values associated with them. Maps provide efficient lookups, additions, and deletions.

Creating and Initializing Maps

  1. Creating a Map Using make: You can create a map using the make function, specifying the key and value types.

    var m map[string]int
    m = make(map[string]int)
  2. Creating and Initializing a Map Using a Composite Literal: You can also create and initialize a map using a composite literal.

    m := map[string]int{
        "apple":  1,
        "banana": 2,
    }

Adding and Updating Elements

You can add or update elements in a map by assigning a value to a key.

m["orange"] = 3
m["apple"] = 4 // Updating the value for the key "apple"

Accessing Elements

You can access elements in a map using the key.

appleCount := m["apple"]
fmt.Println("Apple count:", appleCount)

Deleting Elements

You can delete elements from a map using the delete function.

delete(m, "banana")

Checking if a Key Exists

You can check if a key exists in a map using the value and ok idiom.

val, ok := m["banana"]
if ok {
    fmt.Println("Banana count:", val)
} else {
    fmt.Println("Banana does not exist")
}

Iterating Over a Map

You can iterate over a map using a for loop with the range keyword.

for key, value := range m {
    fmt.Println("Key:", key, "Value:", value)
}

Map with Struct Values

Maps can hold values of any type, including structs.

type Person struct {
    Name string
    Age  int
}
 
people := map[string]Person{
    "John": {Name: "John Doe", Age: 30},
    "Jane": {Name: "Jane Smith", Age: 25},
}

Example: Comprehensive Map Usage

Here is a complete example demonstrating various operations with maps:

package main
 
import (
    "fmt"
)
 
func main() {
    // Creating and initializing a map
    fruits := map[string]int{
        "apple":  5,
        "banana": 3,
        "orange": 4,
    }
 
    // Adding and updating elements
    fruits["grape"] = 7
    fruits["apple"] = 10
 
    // Accessing elements
    fmt.Println("Apple count:", fruits["apple"])
 
    // Checking if a key exists
    val, ok := fruits["banana"]
    if ok {
        fmt.Println("Banana count:", val)
    } else {
        fmt.Println("Banana does not exist")
    }
 
    // Deleting elements
    delete(fruits, "orange")
 
    // Iterating over a map
    for key, value := range fruits {
        fmt.Println("Key:", key, "Value:", value)
    }
 
    // Map with struct values
    type Person struct {
        Name string
        Age  int
    }
 
    people := map[string]Person{
        "John": {Name: "John Doe", Age: 30},
        "Jane": {Name: "Jane Smith", Age: 25},
    }
 
    for username, person := range people {
        fmt.Printf("Username: %s, Name: %s, Age: %d\n", username, person.Name, person.Age)
    }
}

Key Points

  • Unordered: Maps do not maintain any order for keys and values.
  • Efficient Lookups: Maps provide efficient key lookups and are ideal for scenarios where you need quick data retrieval.
  • Zero Values: If a key does not exist in the map, accessing it returns the zero value for the map’s value type.
  • Concurrency: Maps are not safe for concurrent use. If you need to use a map across multiple goroutines, you must use synchronization mechanisms like sync.Mutex.