2012-11-08 49 views
2

我寫了一個函數,它會從map [string] Foo返回一個排序好的字符串片段。我很好奇創建一個通用例程的最佳方法是什麼,該例程可以從任何類型的字符串作爲關鍵字返回已排序的字符串片段。Go是否允許爲具有特定鍵類型的地圖指定接口?

有沒有辦法使用接口規範來做到這一點?例如,有沒有什麼辦法可以做這樣的事情:

type MapWithStringKey interface { 
    <some code here> 
} 

要實現上面的接口,類型將需要字符串作爲鍵。然後,我可以編寫一個通用函數,返回一個排序的鍵列表來滿足類型。

這是用我目前最好的解決方案體現模塊:

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

我被迫碼型爲斷言即使在編譯時每個支持的類型,我們應該知道確切mapWithStringKey參數的類型。

+0

恐怕你需要仿製藥。 Go語言中不包含泛型語言,足夠着名。這就是說,沒有太多的情況下,使用泛型將真正簡化問題:它們通常會增加更多層次和複雜性。 –

+0

我很害怕那個......哦。 –

回答

5

您不能使部分類型。但是你可以定義哪些服務你的目的的接口:

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 
} 

這裏試試:http://play.golang.org/p/vKfri-h4Cp

+0

你的解決方案沒有解決真正的問題:對於每個不同類型的字符串作爲鍵,你必須編寫另一個Keys()函數。使用反射會導致更簡單的解決方案,這也需要對每種類型進行修改:[請參閱此處基於反射的單一func解決方案](http://play.golang.org/p/ROsq9u40PP) –

+1

我將上面的評論反饋給我。我認爲你的解決方案比基於反射的解決方案更好,即使它有點冗長。要求使用Keys()方法將允許編譯時檢查,並且所添加的方法可以位於類型的代碼旁邊。 –

+1

。編譯器也優化(內聯)這個代碼,它不能爲單功能解決方案做。而且,當字符串映射作爲數據結構有點天真時,這也可以很好地擴展。 – simonmenke

0

希望幫助(去-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)) 
} 
相關問題