2015-10-16 85 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”结构的字段。