go – 使代码更通用

我有一个程序,其中许多功能在不同的结构中是相似的,但是,我最终一次又一次地编写这些函数,尤其是因为内部处理的变量具有不同的结构.

我在这里写了一个示例代码.

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
}

如果您注意到,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”结构的字段.

点赞