2016-02-12 34 views
3

我們假設我有一張地圖:map[string]string。我想獲得這張地圖的排序鍵列表。所以我可以做這樣的事情:如何在Go中獲得已排序的地圖鍵列表?

func SortedMapKeys(m map[string]string) (keyList []string) { 
    for key := range m { 
     keyList = append(keyList, key) 
    } 
    sort.Strings(keyList) 
    return 
} 

然後,我將有另一種類型的地圖map[string]bool。我想獲得它的鑰匙也。但問題是函數SortedMapKeys接受map[string]string參數。所以我需要編寫完全相同的功能,只有一個區別 - 它會接受map[string]bool

由於顯而易見的原因,它不是一個選項。如果有一天我想改變我如何得到和排序我的密鑰的邏輯,我將需要跟蹤和更新所有這些功能。此外,我將不得不爲所有這些函數編寫相同的單元測試,因爲它們的實體是100%相等的(代碼複製),所以這些函數實際上執行相同的操作。

有什麼辦法可以創建一個通用函數,它可以接受任何的map[string]

回答

5

map[string]bool由於和map[string]stringmap[string]Whatever都是不同的類型,以創建單個函數所有可能map[string]*類型的鍵進行排序的唯一方法是通過反射。

func SortedMapKeys(m interface{}) (keyList []string) { 
    keys := reflect.ValueOf(m).MapKeys() 

    for _, key := range keys { 
     keyList = append(keyList, key.Interface().(string)) 
    } 
    sort.Strings(keyList) 
    return 
} 

對於在中間的解決方案,因爲有可能的類型只有少數幾個組合您關注的是,你可以使用一種類型的開關來提取鍵

func SortedMapKeys(m interface{}) (keyList []string) { 
    switch m := m.(type) { 
    case map[string]string: 
     for k := range m { 
      keyList = append(keyList, k) 
     } 
    case map[string]bool: 
     for k := range m { 
      keyList = append(keyList, k) 
     } 
    default: 
     panic("unknown map type") 
    } 

    sort.Strings(keyList) 
    return 
} 
1

這裏是我的0.02 $。由於鍵提取邏輯是不可能改變,你希望把一切都在一個地方,你可以創建變種,並從中選擇非空地圖:

type MapVariant struct { 
    Bool map[string]bool 
    String map[string]string 
} 

func SortedMapKeys(variant MapVariant) (keyList []string) { 
    if variant.String != nil { 
     for k := range variant.String { 
      keyList = append(keyList, k) 
     } 
     goto SORT 
    } 
    if variant.Bool != nil { 
     for k := range variant.Bool { 
      keyList = append(keyList, k) 
     } 
     goto SORT 
    } 

SORT: 
    sort.Strings(keyList) 
    return 
} 

當然你也可以通過添加更多的條件,但我儘量避免goto語句個人發現它更清晰。

然後你可以使用的功能等:

SortedMapKeys(MapVariant{ 
    Bool: map[string]bool{"a": true, "b": false} 
}) 
SortedMapKeys(MapVariant{ 
    String: map[string]string{"c": "v1", "b": "v2"} 
}) 
+0

謝謝您的回答,但我不知道,這在解決任務的慣用方式。仍然。由於我重複了收集鍵的邏輯(即使它在同一個方法中),我將不得不編寫單元測試來檢查每個重複的代碼片段。如果有一天我會支持5種地圖呢? 10? 20?如果這段代碼將被組織爲一個庫,並且程序員將要收集map [string] SomeCustomStruct的密鑰,該怎麼辦? – RhinoLarva

相關問題