With the release of Go 1.18, this entire package can thankfully be replaced with the functions demonstrated below:
package main
import (
"fmt"
"golang.org/x/exp/maps"
)
func ContainsKey[K, V comparable](m map[K]V, target V) bool {
for _, v := range m {
if v == target {
return true
}
}
return false
}
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
fmt.Println(maps.Keys(m))
fmt.Println(maps.Values(m))
m2 := map[string]int{}
maps.Copy(m2, m)
fmt.Println(maps.Keys(m2))
fmt.Println(maps.Values(m2))
fmt.Println(ContainsKey(m2, 3))
fmt.Println(ContainsKey(m2, 4))
}go get https://github.com/drgrib/mapsThis package provides type-safe implementations of "missing" map functions:
ContainsKey- check if map contains keyContainsValue- check if map contains valueGetKeys- get keys of a mapGetValues- get values of a mapCopy- deep copy of a map
implemented with these patterns
ContainsKeyKV(map[ktype]vtype, k ktype) boolContainsValueKV(map[ktype]vtype, v vtype) boolGetKeysKV(map[ktype]vtype) []ktypeGetValuesKV(map[ktype]vtype) []vtypeCopyKV(map[ktype]vtype) map[ktype]vtype
where K and V are the key and value for maps combining Go basic types, including but not limited to:
StringStringStringIntIntStringStringFloat32StringFloat64Float32BoolFloat64BoolIntBoolStringBool
The package extends beyond implementing these functions only for these basic type pairings. You can generate them for any map type, including maps with keys and values that are pointers, custom types, or interface{}.
There are two ways to do this. One is by installing and calling the mapper tool, which can be considered a sort of sibling to the stringer tool. The other is programmatically by using the maptemplate library called within the source code of mapper and the code used to generate the basic type map functions in this package.
mapper can be installed using
go get -u github.com/drgrib/maps/cmd/mapperThen used with the go generate like this:
//go:generate mapper -types string:CustomTypeOr directly on the commandline with the same command:
mapper -types string:CustomTypeWhich will generate the file map_string_customtype.go that infers its package from surrounding .go files or the current folder name if no other files are found:
package maps
func ContainsKeyStringCustomType(m map[string]CustomType, k string) bool {
_, ok := m[k]
return ok
}
func ContainsValueStringCustomType(m map[string]CustomType, v CustomType) bool {
for _, mValue := range m {
if mValue == v {
return true
}
}
return false
}
func GetKeysStringCustomType(m map[string]CustomType) []string {
keys := []string{}
for k, _ := range m {
keys = append(keys, k)
}
return keys
}
func GetValuesStringCustomType(m map[string]CustomType) []CustomType {
values := []CustomType{}
for _, v := range m {
values = append(values, v)
}
return values
}
func CopyStringCustomType(m map[string]CustomType) map[string]CustomType {
copyMap := map[string]CustomType{}
for k, v := range m {
copyMap[k] = v
}
return copyMap
}If generics are implemented for Go 2.0, these functions can be covered by a single file, without the need for the mapper tool and its underlying generation packages. Until then, there is this package.