genericsyncmap is a type-safe generic wrapper for Go's sync.Map. It provides the full Go 1.24 sync.Map API without caller-side type assertions, plus typed iteration and collection helpers.
- Type-safe keys and values
- Safe concurrent access without external locking
- Full method parity with Go 1.24's
sync.Map All,Keys,Values, andLenhelpers- Zero dependencies outside the standard library
go get github.com/donomii/genericsyncmapGo 1.24 or newer is required.
The zero value of Map is ready for use:
package main
import (
"fmt"
"github.com/donomii/genericsyncmap"
)
func main() {
var m syncmap.Map[string, int]
m.Store("apple", 10)
m.Store("banana", 20)
if val, ok := m.Load("apple"); ok {
fmt.Printf("apple: %d\n", val)
}
m.Delete("banana")
m.Clear()
}SyncMap[K, V] remains an alias for Map[K, V], and NewSyncMap[K, V]() remains available for compatibility. Like sync.Map, a Map must not be copied after first use.
val, loaded := m.LoadOrStore("cherry", 5)
val, loaded = m.LoadAndDelete("apple")
prev, loaded := m.Swap("grape", 30)
swapped := m.CompareAndSwap("grape", 30, 35)
deleted := m.CompareAndDelete("grape", 35)CompareAndSwap and CompareAndDelete require the old value to be comparable, matching sync.Map behavior. They panic if given a non-comparable old value.
Use All with Go's range-over-function syntax:
for key, value := range m.All() {
fmt.Printf("%s: %d\n", key, value)
}Range is also available. Returning false stops iteration:
m.Range(func(key string, value int) bool {
fmt.Printf("%s: %d\n", key, value)
return true
})All and Range do not necessarily observe a consistent snapshot if the map is modified concurrently. Keys, Values, and Len inherit that behavior. Len iterates over the entire map in O(N) time.
The benchmarks compare genericsyncmap.Map, raw sync.Map, and a built-in map protected by sync.RWMutex. All mixed-workload maps are prepopulated with 1,024 keys, and operations and keys are selected independently.
Results from Go 1.26.2 on an Apple M5 Pro (darwin/arm64):
| Benchmark | genericsyncmap | sync.Map | map + RWMutex |
|---|---|---|---|
| Load hit | 5.18 ns/op | 4.68 ns/op | 3.78 ns/op |
| Store existing | 26.4 ns/op | 24.8 ns/op | 8.00 ns/op |
| Concurrent 50/50 load/store | 19.4 ns/op | 20.6 ns/op | 74.2 ns/op |
These results are a single-machine measurement, not a performance guarantee. Run the benchmarks for the workload and hardware that matter to you:
go test -bench . -benchmemLike sync.Map, this package is optimized for workloads where entries are written once and read many times, or where goroutines access disjoint key sets.
MIT