GO :具有不同类型输入的模型(或接口)函数

GO : model ( or interface ) function with input of different types

现在我有一个使用并行算法计算统计数据的小应用程序。 现在我在扩展某些功能时遇到了问题。我会尽快解释。 应用程序是建立在狂欢框架上的。 "stat" controller 的动作之一接受传入 POST json。解析它。并为任务和结果生成两个通道(goroutines)。所有这一切都像一个魅力。但是我在模型方面遇到了麻烦。我编写了能够线性扩展模型数量的代码,但目前只有一个在工作。

而且这个扩展并不是所有的方法都采用的

在代码的某些部分我有这个:

for t := range in {
        for sourceName, charts := range t.Request.Charts {

            var cacheData []byte
            var deserializedData models.StatModel

            //determine the model type
            switch sourceName {
            case "noagg":
                deserializedData = new(models.NoaggModel)
            case "acsi":
                deserializedData = new(models.AcsiModel)
            }

            cache_err := cache.Get(string(string(sourceName) + "_" + string(t.Date)), &cacheData);
            if cache_err != nil {
                panic("the cache is empty")
            }

            marshal_error := json.Unmarshal([]byte(cacheData), &deserializedData)
            if marshal_error == nil {

            }

            deserializedData.FilterData(t.Request.Filters)

            deserializedData.ClusterData(t.Request.Filters)

            w := Work{}
            for _, chart := range charts {
                countedData := ChartElements{}

                if marshal_error == nil {
                    countedData = deserializedData.CountDataForChart(string(chart.Name))
                }else {
                    panic("some is bad")
                }

                w.Name, w.Data = chart.Name, countedData
                out <- w
            }
        }
    }

Noagg 模型和 Asci 模型正在实现 "stat" 模型的相同接口:

type StatModel interface {
    FilterData(Filter)
    ClusterData(Filter)
    CountDataForChart(string)[]ChartElement
    GroupByTreeGroups(Filter)[]OrgPack
}

但现在我必须添加一些具有相同界面的新模型,但是有代码,我无法扩展。我不记得怎么做了..

func statCount(model NoaggRow, f func(NoaggRow) float64) float64 {
    countedStat := f(model)
    return countedStat
}

func Count(model NoaggRow, name string) float64{

    m := map[string]func(NoaggRow) float64 {
        "HOLD" : HOLD,
        "INB"  : INB,
        "AHT"  : AHT,
        "RING" : RING,
        "TALK" : TALK,
        "ACW"  : ACW,
        "OCC"  : OCC,
    }
    countedStat := statCount(model, m[name])
    return countedStat
}

我需要的方法与 ASCI 模型相同。对于 AcsiRow 而不是 NoaggRow。如何使此输入参数类型动态化或如何使方法对所有模型通用。只有 "map[string]func(......Row)" 的数组和名称在这个地方会有所不同。谁能帮我解决这个问题?

如果映射中的函数(即 HOLD()INB() 等)不需要比 StatModel 接口提供的更多的模型访问权限,那么您的要求应该可以通过更改这些函数以接收 StatModel 而不是 NoaggRow:

func HOLD(s StatModel) float64 {
    ...
}

那么你要添加的AcsiRow函数可以有相同的签名,statCount和Count可以改写如下:

func statCount(model StatModel, f func(StatModel) float64) float64 {
    countedStat := f(model)
    return countedStat
}

func Count(model StatModel, name string) float64 {
    m := map[string]func(StatModel) float64 {
        "HOLD" : HOLD,
        "INB"  : INB,
        "AHT"  : AHT,
        "RING" : RING,
        "TALK" : TALK,
        "ACW"  : ACW,
        "OCC"  : OCC,
        // Map AcsiModel functions here, let's call them ACSIn here
        // (you mentioned that the names would be different, so
        // I assume they don't get in the way of the functions
        // above):
        "ACSI1": ACSI1,
        "ACSI2": ACSI2,
        "ACSI3": ACSI3,
    }
    countedStat := statCount(model, m[name])
    return countedStat
}

免责声明:这只是一个基于我在 post 中看到的内容的想法。我对 Revel 一无所知,也许我因此错过了一些由 Revel 上下文引起的重要细节,这些细节会阻止实施这种方法。

根据评论更新

使用type assertions启用HOLDOCC等函数来访问结构特定的属性,如下所示:

func HOLD (s StatModel) float64 {
    noagg, ok := s.(NoaggRow) // typecast from StateModel to NoaggRow
    if !ok {
        // Looks like the caller did not pass a matching model/name pair into Count().
        // Error handling...
    }
    attr := noagg.AttributeSpecificToNoaggRow
    ...
}

这在运行时可能看起来有点冒险,但如果调用者总是将匹配的 model/name 值对传递给 Count() (我假设它这样做),类型转换应该是安全的。