2015-10-16 60 views
4

我有一個程序,許多功能在不同的結構中是相似的,但是,我最終一次又一次地寫這些函數,尤其是因爲正在處理的變量是不同的結構。使代碼更通用

我在這裏寫了一個示例代碼。

In Go Playgroud

package main 

import "fmt" 

func (a *Match) Add(v Match) { 
    a.Runs += v.Runs 
    a.Points += v.Points 
} 

type Match struct { 
    Runs uint64 
    Points uint64 
} 

func (a *Activity) Add(v Activity) { 
    a.Walk += v.Walk 
    a.Jog += v.Jog 
} 

type Activity struct { 
    Walk uint64 
    Jog uint64 
} 

func GetDailyMatches() map[string]Match { 
    var dailyMatches map[string]Match 

    Match1, Match2 := Match{5, 10}, Match{1, 2} 
    dailyMatches = make(map[string]Match) 
    dailyMatches["01"] = Match1 
    dailyMatches["02"] = Match2 
    dailyMatches["03"] = Match1 
    dailyMatches["04"] = Match2 
    return dailyMatches 
} 

func GetDailyActivities() map[string]Activity { 
    var dailyActivities map[string]Activity 

    Activity1, Activity2 := Activity{5, 10}, Activity{1, 2} 
    dailyActivities = make(map[string]Activity) 
    dailyActivities["01"] = Activity1 
    dailyActivities["02"] = Activity2 
    dailyActivities["03"] = Activity1 
    dailyActivities["04"] = Activity2 
    return dailyActivities 
} 

func main() { 
    fmt.Println(CalculateMatchSummary("01", "03")) 
    fmt.Println(CalculateActivitySummary("02", "04")) 
    fmt.Println(CalculateMatchSummary("01", "03")) 
    fmt.Println(CalculateActivitySummary("02", "04")) 
} 

func CalculateMatchSummary(start, end string) (total Match) { 
    dailyMatches := GetDailyMatches() 
    for day, value := range dailyMatches { 
     if day < start { 
      continue 
     } else if day > end { 
      continue 
     } else { 
      total.Add(value) 
     } 
    } 
    return 
} 

func CalculateActivitySummary(start, end string) (total Activity) { 
    dailyActivities := GetDailyActivities() 
    for day, value := range dailyActivities { 
     if day < start { 
      continue 
     } else if day > end { 
      continue 
     } else { 
      total.Add(value) 
     } 
    } 
    return 
} 

如果您發現,無論是MatchActivity具有相同的功能和相同的結構,不同之處在於內部,它們是不同的結構。

有沒有一種簡單的方法可以讓Golang本身的代碼變得更爲通用(Go的泛型,Go不在這裏)。

+0

你可以只是把方法中的if塊.. – ergonaut

+0

@ergonaut'total'類型是不同的。它會繼續工作嗎? – Sundar

+0

我想不是。 https://golang.org/doc/faq#generics – ergonaut

回答

1

去有一個漂亮的包「反映」。你可以嚴格來說而不是通用性,但你可以得到相同行爲的統一代碼。 我已經改變了你的遊樂場了一下:https://play.golang.org/p/bfqZsFOgVQ

主要部分:

func AddTwo(a, b interface{}) interface{} { 
    va := reflect.ValueOf(a) 
    vb := reflect.ValueOf(b) 
    res := reflect.New(reflect.TypeOf(a)).Elem() 
    if va.Kind() != reflect.Struct && vb.Kind() != reflect.Struct { 
     return nil 
    } 

    na, nb := va.NumField(), vb.NumField() 
    if na != nb { 
     return nil 
    } 

    for i := 0; i < na; i++ { 
     // additional verification needed here 
     fa := va.Field(i).Uint() 
     fb := vb.Field(i).Uint() 
     fr := fa + fb 
     res.Field(i).SetUint(fr) 
    } 

    return res.Interface() 
} 

我使用反映來檢查我給定的結構的領域。如果兩者都是uint64,我可以反射性地添加它們。如果你的結構包含許多uint64,它可以將它們全部添加!

請注意,在調用此函數後,必須將生成的接口轉換爲給定的結構類型。這就是爲什麼這不是通用的,因爲返回類型是一個接口,而不是匹配或活動。

編輯:甚至不需要返回一個新的結構。您可以通過調用.SetUint()方法來簡單地更新「a」結構的字段。