0
0
GoHow-ToBeginner · 4 min read

How to Use sync.Map in Go: Simple Guide with Examples

In Go, sync.Map is a concurrent map designed for safe access by multiple goroutines without explicit locking. You use methods like Store, Load, and Delete to add, retrieve, and remove items safely. It is ideal for cases where many goroutines read, write, and delete keys concurrently.
📐

Syntax

The sync.Map type provides a concurrent map with these main methods:

  • Store(key, value): Adds or updates a key-value pair.
  • Load(key): Retrieves the value for a key and a boolean indicating if it was found.
  • Delete(key): Removes a key and its value.
  • LoadOrStore(key, value): Loads the existing value or stores and returns the new one.
  • Range(func(key, value) bool): Iterates over all key-value pairs.

This map is safe for concurrent use without extra locks.

go
var m sync.Map

// Store a value
m.Store("foo", 42)

// Load a value
value, ok := m.Load("foo")

// Delete a key
m.Delete("foo")

// Load or store
actual, loaded := m.LoadOrStore("foo", 100)

// Iterate all
m.Range(func(key, value interface{}) bool {
    fmt.Println(key, value)
    return true // continue iteration
})
💻

Example

This example shows how to safely store, load, and delete keys in sync.Map concurrently.

go
package main

import (
	"fmt"
	"sync"
)

func main() {
	var m sync.Map

	// Store some values
	m.Store("apple", 5)
	m.Store("banana", 10)

	// Load and print a value
	if val, ok := m.Load("apple"); ok {
		fmt.Println("apple:", val)
	} else {
		fmt.Println("apple not found")
	}

	// Delete a key
	m.Delete("banana")

	// Try to load deleted key
	if _, ok := m.Load("banana"); !ok {
		fmt.Println("banana deleted")
	}

	// Iterate all keys
	m.Range(func(key, value interface{}) bool {
		fmt.Printf("%v -> %v\n", key, value)
		return true
	})
}
Output
apple: 5 banana deleted apple -> 5
⚠️

Common Pitfalls

Common mistakes when using sync.Map include:

  • Using it like a regular map without understanding it is optimized for concurrent use cases.
  • Expecting type safety: sync.Map stores keys and values as interface{}, so you must type assert when loading.
  • Using Range to modify the map concurrently can cause unexpected behavior.
  • Overusing sync.Map for simple cases where a normal map with a mutex is more efficient.

Example of type assertion:

go
var m sync.Map
m.Store("key", 123)

// Wrong: assuming value is int without check
// val := m.Load("key").(int) // panics if key missing

// Right: check type assertion
val, ok := m.Load("key")
if ok {
	if num, ok := val.(int); ok {
		fmt.Println("Value is", num)
	} else {
		fmt.Println("Value is not an int")
	}
} else {
	fmt.Println("Key not found")
}
📊

Quick Reference

MethodDescription
Store(key, value)Add or update a key-value pair
Load(key)Retrieve value and existence boolean
Delete(key)Remove a key and its value
LoadOrStore(key, value)Load existing or store new value
Range(func(key, value) bool)Iterate all key-value pairs

Key Takeaways

Use sync.Map for safe concurrent access without explicit locks.
Always check type assertions when loading values from sync.Map.
Avoid modifying the map inside Range to prevent unexpected behavior.
sync.Map is best for cases with many goroutines reading and writing concurrently.
For simple or single-threaded cases, a normal map with a mutex may be more efficient.