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

huangapple go评论89阅读模式
英文:

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

问题

我写了一个函数,它可以从一个map[string]Foo返回一个排序后的字符串切片。我想知道创建一个通用的例程来从任何类型的map中返回一个排序后的字符串切片的最佳方法是什么。

有没有办法使用接口规范来实现这个?例如,有没有办法做到这样:

type MapWithStringKey interface {
    <这里放一些代码>
}

要实现上面的接口,类型需要将字符串作为键。然后,我可以编写一个通用函数,返回满足类型要求的键的排序列表。

这是我目前使用reflect模块的最佳解决方案:

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)
            }
            // ... 根据需要添加更多的情况
        default:
            log.Fatalf("错误:SortedKeys()不处理%s\n", typ)
        }
        sort.Strings(keys)
    } else {
        log.Fatalln("错误:SortedKeys()的参数不是map[string]...")
    }
    return keys
}

点击查看Go Playground版本

尽管在编译时我们应该知道mapWithStringKey参数的确切类型,但我被迫为每个支持的类型编写类型断言。

英文:

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 {
    &lt;some code here&gt;
}

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 &amp;&amp; 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(&quot;Error: SortedKeys() does not handle %s\n&quot;, typ)
		}
		sort.Strings(keys)
	} else {
		log.Fatalln(&quot;Error: parameter to SortedKeys() not map[string]...&quot;)
	}
	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

得分: 5

你不能创建部分类型。但是你可以定义一个满足你需求的接口:

type SortableKeysValue interface {
    // 返回需要排序的字符串
    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
}

在这里尝试一下:http://play.golang.org/p/vKfri-h4Cp

英文:

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

得分: 0

希望能帮到你(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))
}
英文:

Hope that helps (go-1.1):

package main

import (
	&quot;fmt&quot;
&quot;reflect&quot;
)

var m = map[string]int{&quot;a&quot;: 3, &quot;b&quot;: 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(&quot;%#v\n&quot;, MapKeys(m))
}

huangapple
  • 本文由 发表于 2012年11月8日 23:21:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/13291958.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定