6

我有一个名为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 是否支持泛型,我应该如何修复我的代码?

4

3 回答 3

7

1- Golang 是强类型语言,所以map[int]interface{}不兼容map[interface{}]interface{}.
int与 不同类型interface{},请参阅:Go: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包用于某些用例,但会降低性能(速度)。
参见:反射定律

于 2016-08-22T04:40:01.263 回答
6

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

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

工作代码

于 2016-08-22T05:57:58.883 回答
1

从 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

请注意,根据当前提案,类型参数上的类型约束K是预先声明的标识符comparable,而不是any.

这是因为映射键必须支持比较运算符。因此,您必须仅限K于可比较的类型。


或者,基于这个被接受的提议,新的包maps也可以用来完成同样的事情。但是,这还没有在标准库中。相反,它被包含在其中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

于 2021-06-17T13:11:24.283 回答