如何获取地图的key

How to get keys of map

我有一个名为Keys()的函数来获取地图的所有键,代码如下:

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
}

但是我得到了

cannot use m2 (type map[int]interface {}) as type map[interface {}]interface {} in argument to Keys

Go 是否支持泛型?我应该如何修复我的代码?

1- Golang 是强类型语言,所以 map[int]interface{}map[interface{}]interface{} 不兼容。
intinterface{} 的类型不同, 并查看:Go: What's the meaning of interface{}?

2- 不,Golang 不支持泛型,这很好,因为它使语言变得简单和快速。


您有一些选择:

如果您不想更改使用的地图类型:
1- 您可以将函数编辑为:func Keys(m map[int]interface{}) []int,就像这个工作示例代码:

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
}

输出(可能顺序不对):

[2 3]

2- 或者您可以将函数编辑为:func Keys(m map[int]interface{}) []interface{},就像这样的工作示例代码:

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
}

输出(可能顺序不对):

[2 3]

如果您不想更改使用的 Keys 函数:
3- 您可以将地图编辑为:map[interface{}]interface{},就像这个工作示例代码:

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-您也可以在某些用例中使用 reflect 包,但会降低性能(速度)。
请参阅:The Laws of Reflection

除了 Amd 的解决方案,如果您不想更改使用的地图类型,您还可以使用 reflect 库。

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

}

请注意,如果您使用此解决方案,Keys 返回的键将包含包装在接口本身中的每个键值。因此,要获得实际值,您可能必须执行类型断言:

k := Keys(m2)
k1 := k[0].(int) // k[0] is an interface value, k1 is an int

Working Code.

从 Go 1.18(测试版发布)开始,该语言添加了类型参数,您可以轻松编写如下函数:

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
}

用法示例:

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
}

游乐场:https://gotipplay.golang.org/p/pdsI2H7w-N4

注意,基于current proposal,类型参数K的类型约束是预先声明的标识符comparable,而不是any

这是因为地图键必须支持comparison operators。因此,您必须将 K 限制为仅可比较的类型。


或者基于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,因此不在 Go 1 兼容性承诺范围内

maps.Keys和上面的函数的区别在于maps.Keys是在M上参数化的(除了KV),与近似约束 ~map[K]V。这允许所有具有底层 map:

的已定义类型
type MyMap map[string]int

用法基本相同:

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
}

游乐场:https://gotipplay.golang.org/p/Bx11jmyifAg