How to get keys of map
Solution 1
1- Golang is strongly typed language, So the map[int]interface{}
is not compatible with map[interface{}]interface{}
.
int
is different type than interface{}
,
and see: Go: What's the meaning of interface{}?
2- No, Golang doesn't support generics, and this is very good, because it makes language simple and fast.
You have some options:
If you don't want to change the type of map used:
1- You may edit the function to: func Keys(m map[int]interface{}) []int
, like this working sample code:
package main
import "fmt"
func main() {
m2 := map[int]interface{}{
2: "string",
3: "int",
}
fmt.Println(Keys(m2))
}
func Keys(m map[int]interface{}) []int {
keys := make([]int, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
return keys
}
output ( may not be in order):
[2 3]
2- Or you may edit the function to: func Keys(m map[int]interface{}) []interface{}
, like this working sample code:
package main
import "fmt"
func main() {
m2 := map[int]interface{}{
2: "string",
3: "int",
}
fmt.Println(Keys(m2))
}
func Keys(m map[int]interface{}) []interface{} {
keys := make([]interface{}, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
return keys
}
output ( may not be in order):
[2 3]
If you don't want to change the Keys
function used:
3- You may edit the map to: map[interface{}]interface{}
, like this working sample code:
package main
import "fmt"
func main() {
m2 := map[interface{}]interface{}{
2: "string",
3: "int",
}
fmt.Println(Keys(m2))
}
func Keys(m map[interface{}]interface{}) []interface{} {
keys := make([]interface{}, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
return keys
}
4- Also you may use reflect
package for some use cases, but with the performance (speed) penalty.
And See: The Laws of Reflection
Solution 2
Besides Amd's solution, you can also make use of the reflect library if you do not want to change the type of map used.
func main() {
m2 := map[int]interface{}{
2: "string",
3: "int",
}
k := Keys(m2)
fmt.Printf("Keys: %v\n", k)
}
func Keys(m interface{}) (keys []interface{}) {
v := reflect.ValueOf(m)
if v.Kind() != reflect.Map {
fmt.Errorf("input type not a map: %v", v)
}
for _, k := range v.MapKeys() {
keys = append(keys, k.Interface())
}
return keys
}
Note that if you use this solution, the returned keys from Keys
will contain each key value wrapped in an interface itself. So to get the actual value you might have to do type assertions:
k := Keys(m2)
k1 := k[0].(int) // k[0] is an interface value, k1 is an int
Solution 3
Starting from Go 1.18 (released in beta) the language adds type parameters and you are be able to easily write a function like this:
func Keys[K comparable, V any](m map[K]V) []K {
keys := make([]K, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}
Example usage:
func main() {
m := map[int]string{2: "string", 3: "int"}
keys := Keys(m)
fmt.Println(keys) // [2 3]
fmt.Println(reflect.TypeOf(keys)) // []int
m2 := map[string]int{"a": 1, "b": 2}
keys2 := Keys(m2)
fmt.Println(keys2) // [a b]
fmt.Println(reflect.TypeOf(keys2)) // []string
}
Playground: https://gotipplay.golang.org/p/pdsI2H7w-N4
Note that, based on the current proposal, the type constraint on the type parameter K
is the predeclared identifier comparable
, instead of any
.
This is because map keys must support comparison operators. Therefore you must restrict K
to comparable types only.
Alternatively based on this accepted proposal the new package maps
is also available to accomplish the same thing. However this is not yet in the standard library. Instead it was included in golang.org/x/exp
, therefore it is not covered by Go 1 compatibility promise.
The difference between maps.Keys
and the function above is that maps.Keys
is parametrized on M
(other than K
and V
), with the approximate constraint ~map[K]V
. This allows all defined types with underlying map
:
type MyMap map[string]int
The usage is basically the same:
package main
import (
"fmt"
"reflect"
"golang.org/x/exp/maps"
)
func main() {
m := map[int]string{2: "string", 3: "int"}
keys := maps.Keys(m)
fmt.Println(keys) // [2 3]
fmt.Println(reflect.TypeOf(keys)) // []int
}
Playground: https://gotipplay.golang.org/p/Bx11jmyifAg
Comments
-
GoingMyWay almost 2 years
I have a function named
Keys()
to get all the keys of a map, here is the code:func main() { m2 := map[int]interface{}{ 2:"string", 3:"int", } fmt.Println(Keys(m2)) } func Keys(m map[interface{}]interface{}) (keys []interface{}) { for k := range m { keys = append(keys, k) } return keys }
But I got
cannot use m2 (type map[int]interface {}) as type map[interface {}]interface {} in argument to Keys
Does Go support generics and how should I fix my code?