通用地图值

mvr*_*yan 8 hashmap go

当我想以类似的方式使用地图的键但是地图中的值不同时,我遇到过这个问题几次.我以为我可以编写一个函数,它接受我想要的键类型接口{}作为值类型,但它不起作用.

func main() {
    mapOne := map[string]int
    mapTwo := map[string]double
    mapThree := map[string]SomeStruct

    useKeys(mapOne)
}
func useKeys(m map[string]interface{}) {
    //something with keys here
}
Run Code Online (Sandbox Code Playgroud)

不确定是否有一种优雅的方式来做到这一点我只是感觉腰部完全重写简单的东西为不同的价值观.

bla*_*een 15

去1.18

您可以为此编写一个带有类型参数(通用)的函数:

func useKeys[V any](m map[string]V) V {
    return m["foo"]
}
Run Code Online (Sandbox Code Playgroud)

并将其用作:

func main() {
    m1 := map[string]int{"foo": 1}
    m2 := map[string]float64{"foo": 4.5}
    m3 := map[string]*SomeStruct{}

    fmt.Println(useKeys(m1))
    fmt.Println(useKeys(m2))
    fmt.Println(useKeys(m3))

}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,类型参数V与映射值统一,这样您就可以显式强制 的调用者useKeys传递键为stringonly 的映射。

您可以在 GoTip Playground 上看到这一点:https://gotipplay.golang.org/p/epFA2_9u5l5


Jim*_*imB 13

虽然go中的map和slice本身是通用的,但它们不是协变的(也不是,因为接口不是泛型).这是使用没有泛型的语言的一部分,你将不得不重复一些事情.

如果你真的只需要获取任何旧地图的键,你可以使用反射来做到这一点:

func useKeys(m interface{}) {
    v := reflect.ValueOf(m)
    if v.Kind() != reflect.Map {
        fmt.Println("not a map!")
        return
    }

    keys := v.MapKeys()
    fmt.Println(keys)
}
Run Code Online (Sandbox Code Playgroud)