检索任意映射变量的键

时间:2018-08-21 17:48:53

标签: go casting

我想获取任意映射变量的键。我发现了该函数,该函数复制了PHP array_keys行为:https://www.php2golang.com/method/function.array-keys.html。但是下面的代码:

items := map[string]int{
    "one":   1,
    "two":   2,
    "three": 3,
}
keys := ArrayKeys(items)

引发下一个“编译时”异常:

  

不能将项目(类型map [string] int)用作类型map [interface   {}]接口{}指向ArrayKeys

我在做什么错了?

下面是一个示例:https://play.golang.org/p/0ImqjPJFFiE

3 个答案:

答案 0 :(得分:3)

您应该更改功能以适合您的类型:

func ArrayKeys(elements map[string]int) []string  {
    i, keys := 0, make([]string, len(elements))
    for key, _ := range elements {
        keys[i] = key
        i++
    }
    return keys
}

https://play.golang.org/p/n5kZego0ePY

但是为什么要更改签名?

如果Go中的函数采用空接口,则所有包含的变量都不再具有类型。但是Go是强类型的,因此处理没有类型的变量很困难。如果您提供像您这样的函数,那么代码应该真正处理任何类型。为此,您将需要使用反射包。如果发生错误而错过了某些内容,则程序将发生错误。编写服务器时,它可以运行几个月,然后停止运行。

如果您为每种类型编写一个ArrayKey函数,那么情况就会有所不同。编译器可确保您的代码健壮且不会在那一刻发生恐慌。如果您想尝试将该函数与其他类型的地图一起使用,则代码将无法编译。 Go就是这样工作的。

答案 1 :(得分:2)

在Go中,编写一个简单的函数。例如,

package main

import "fmt"

func main() {

    items := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }

    keys := func(m map[string]int) []string {
        mk := make([]string, 0, len(m))
        for k := range m {
            mk = append(mk, k)
        }
        return mk
    }(items)

    fmt.Printf("%d %q\n", len(keys), keys)
}

游乐场:https://play.golang.org/p/B0kOxAGbQCZ

输出:

3 ["three" "one" "two"]

对于已排序的键,

package main

import (
    "fmt"
    "sort"
)

func main() {

    items := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }

    keys := func(m map[string]int) []string {
        mk := make([]string, 0, len(m))
        for k := range m {
            mk = append(mk, k)
        }
        sort.Strings(mk)
        return mk
    }(items)

    fmt.Printf("%d %q\n", len(keys), keys)
}

游乐场:https://play.golang.org/p/IQLx7gjGk8j

输出:

3 ["one" "three" "two"]

答案 2 :(得分:0)

明确提到的错误:

  

不能将项目(类型map [string] int)用作类型map [interface   {}]接口{}指向ArrayKeys

由于类型不匹配,您遇到了错误。如果要在函数中使用任何类型,则可以使用接口,因为interface{}不等于map[interface{}]interface{}

如果您确实想使用接口,则可以使用interface{}来包装来自maps的数据。否则,您应该使用与上述答案中提到的函数相同的类型作为参数。

package main

import (
    "fmt"
)

func ArrayKeys(elements interface{}) []interface{} {
    i, keys := 0, make([]interface{}, len(elements.(interface{}).(map[string]int)))
    for key, _ := range elements.(interface{}).(map[string]int) {
        keys[i] = key
        i++
    }
    return keys
}

func main() {
    items := map[string]int{
        "one":   1,
        "two":   2,
        "three": 3,
    }
    keys := ArrayKeys(items)
    fmt.Println(keys)
}

Go Playground上工作的代码