【问题标题】:How to get keys of map如何获取地图的键
【发布时间】:2016-08-22 03:57:12
【问题描述】:

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

【问题讨论】:

    标签: generics go go-reflect


    【解决方案1】:

    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

    【讨论】:

      【解决方案2】:

      除了amd的解决方案,如果你不想改变使用的map类型,也可以使用反射库。

      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.

      【讨论】:

        【解决方案3】:

        从 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 的新包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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-13
          • 2016-01-29
          • 1970-01-01
          • 1970-01-01
          • 2021-05-26
          • 2016-05-23
          相关资源
          最近更新 更多