Generics 如何获取地图的关键点

Generics 如何获取地图的关键点,generics,go,go-reflect,Generics,Go,Go Reflect,我有一个名为Keys() func main(){ m2:=映射[int]接口{}{ 2:“字符串”, 3:“int”, } 格式打印LN(图例(m2)) } func键(m映射[接口{}]接口{})(键[]接口{}){ 对于k:=范围m{ keys=追加(keys,k) } 返回键 } 但是我有 cannot use m2 (type map[int]interface {}) as type map[interface {}]interface {} in argument to Keys

我有一个名为
Keys()

func main(){
m2:=映射[int]接口{}{
2:“字符串”,
3:“int”,
}
格式打印LN(图例(m2))
}
func键(m映射[接口{}]接口{})(键[]接口{}){
对于k:=范围m{
keys=追加(keys,k)
}
返回键
}
但是我有

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

Go是否支持泛型以及如何修复代码?

1-Golang是强类型语言,因此
map[int]接口{}
map[interface{}]接口{}
不兼容
int
接口{}
的类型不同, 请参阅:

2-不,Golang不支持泛型,这非常好,因为它使语言简单快速


您有一些选择:

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

主程序包
输入“fmt”
func main(){
m2:=映射[int]接口{}{
2:“字符串”,
3:“int”,
}
格式打印LN(图例(m2))
}
func键(m映射[int]接口{})[]int{
键:=make([]int,len(m))
i:=0
对于k:=范围m{
键[i]=k
我++
}
返回键
}
输出(可能不符合顺序):


2-或者您可以将函数编辑为:
func键(m map[int]interface{})[]interface{}
,如下工作示例代码:

主程序包
输入“fmt”
func main(){
m2:=map[int]接口{}{
2:“字符串”,
3:“int”,
}
格式打印LN(图例(m2))
}
func键(m映射[int]接口{})[]接口{}{
键:=make([]接口{},len(m))
i:=0
对于k:=范围m{
键[i]=k
我++
}
返回键
}
输出(可能不符合顺序):


如果您不想更改所使用的
功能:
3-您可以将映射编辑为:
map[interface{}]interface{}
,如下工作示例代码:

主程序包
输入“fmt”
func main(){
m2:=映射[接口{}]接口{}{
2:“字符串”,
3:“int”,
}
格式打印LN(图例(m2))
}
func键(m映射[接口{}]接口{}][]接口{}{
键:=make([]接口{},len(m))
i:=0
对于k:=范围m{
键[i]=k
我++
}
返回键
}

4-对于某些用例,您也可以使用
reflect
包,但会带来性能(速度)损失。

请参阅:

除了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
.

从Go 1.18开始(2022年初,除非延迟),该语言最终将实现类型参数,您将能够轻松编写如下函数:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    m2 := map[int]interface{}{
        2: "string",
        3: "int",
    }

    keys := Keys(m2)
    fmt.Println(keys)                 // [2 3]
    fmt.Println(reflect.TypeOf(keys)) // []int
}
func Keys[K comparable](m map[K]interface{}) (keys []K) {
    for k := range m {
        keys = append(keys, k)
    }
    return keys
}
请注意,基于,类型参数
K
上的类型约束是预先声明的标识符
compariable
1,而不是
any

这是因为地图键必须支持:

比较运算符
==
=

因此,您必须仅将
K
限制为可比较的类型



1:仍在讨论引入哪些预先声明的标识符;类型参数实现完成后返回检查

map[interface{}]interface{}和map[int]interface{}是不同的类型,这就是为什么会出现错误。也许您可以将m2更改为类型map[interface{}]interface{}
k := Keys(m2)
k1 := k[0].(int) // k[0] is an interface value, k1 is an int
package main

import (
    "fmt"
    "reflect"
)

func main() {
    m2 := map[int]interface{}{
        2: "string",
        3: "int",
    }

    keys := Keys(m2)
    fmt.Println(keys)                 // [2 3]
    fmt.Println(reflect.TypeOf(keys)) // []int
}
func Keys[K comparable](m map[K]interface{}) (keys []K) {
    for k := range m {
        keys = append(keys, k)
    }
    return keys
}