Does Go allow specification of an interface for a map with particular key type?

痴心易碎 提交于 2019-12-10 22:45:17

问题


I wrote a function that would return a sorted slice of strings from a map[string]Foo. I'm curious what is the best way to create a generic routine that can return a sorted slice of strings from any type that is a map with strings as keys.

Is there a way to do it using an interface specification? For example, is there any way to do something like:

type MapWithStringKey interface {
    <some code here>
}

To implement the interface above, a type would need strings as keys. I could then write a generic function that returns a sorted list of keys for fulfilling types.

This is my current best solution using the reflect module:

func SortedKeys(mapWithStringKey interface{}) []string {
    keys := []string{}
    typ := reflect.TypeOf(mapWithStringKey)
    if typ.Kind() == reflect.Map && typ.Key().Kind() == reflect.String {
        switch typ.Elem().Kind() {
        case reflect.Int:
            for key, _ := range mapWithStringKey.(map[string]int) {
                keys = append(keys, key)
            }
        case reflect.String:
            for key, _ := range mapWithStringKey.(map[string]string) {
                keys = append(keys, key)
            }
            // ... add more cases as needed
        default:
            log.Fatalf("Error: SortedKeys() does not handle %s\n", typ)
        }
        sort.Strings(keys)
    } else {
        log.Fatalln("Error: parameter to SortedKeys() not map[string]...")
    }
    return keys
}

Click for Go Playground version

I'm forced to code type assertions for each supported type even though at compile time, we should know the exact type of the mapWithStringKey parameter.


回答1:


You cannot make partial types. But you can define an interface which serves your purpose:

type SortableKeysValue interface {
    // a function that returns the strings to be sorted
    Keys() []string
}

func SortedKeys(s SortableKeysValue) []string {
    keys := s.Keys()
    sort.Strings(keys)
    return keys
}

type MyMap map[string]string

func (s MyMap) Keys() []string {
    keys := make([]string, 0, len(s))
    for k, _ := range s {
        keys = append(keys, k)
    }
    return keys
}

Try it here: http://play.golang.org/p/vKfri-h4Cp




回答2:


Hope that helps (go-1.1):

package main

import (
    "fmt"
"reflect"
)

var m = map[string]int{"a": 3, "b": 4}

func MapKeys(m interface{}) (keys []string) {
    v := reflect.ValueOf(m)
    for _, k := range v.MapKeys() {
        keys = append(keys, k.Interface().(string))
    }
    return
}

func main() {
    fmt.Printf("%#v\n", MapKeys(m))
}


来源:https://stackoverflow.com/questions/13291958/does-go-allow-specification-of-an-interface-for-a-map-with-particular-key-type

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!