Go是否允许为具有特定键类型的映射指定接口?

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
", 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.

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

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
", MapKeys(m))
}