我有一个程序,其中许多功能在不同的结构中是相似的,但是,我最终一次又一次地编写这些函数,尤其是因为内部处理的变量具有不同的结构.
我在这里写了一个示例代码.
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
}
如果您注意到,Match和Activity都具有相同的功能和相同的结构,除了内部它们具有不同的结构.
Golang本身是否有一种简单的方法可以使代码更通用(Go泛型,Go中不存在).
最佳答案 Go有一个漂亮的包“反映”.严格来说,你不能做通用性,但你可以为同一行为统一代码.
我已经改变了你的操场:
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()
}
我使用reflect来检查我给出的struct的字段.如果两者都是uint64,我可以反思地添加它们.如果你的结构包含许多uint64,它可以全部添加!
请注意,必须将生成的接口转换为调用此函数后给定的结构类型.这就是为什么这不是严格的通用,因为返回类型是一个接口,而不是匹配或活动.
编辑:甚至不需要返回一个新结构.您可以通过调用.SetUint()方法简单地更新“a”结构的字段.