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

huangapple go评论73阅读模式
英文:

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

问题

现在我有一个用于使用并行算法计算统计数据的小应用程序。
现在我遇到了一个扩展功能的问题。我会尝试简要解释一下。
该应用程序是基于revel框架构建的。 "stat"控制器的一个动作接收传入的POST json数据。解析它并生成两个通道(goroutines)用于任务和结果。这一切都很顺利。但是我在模型方面遇到了问题。我编写了能够线性扩展模型数量的代码,但目前只有一个模型在工作。

并且并非所有的方法都适用于这种扩展。

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

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

        var cacheData []byte
        var deserializedData models.StatModel

        //确定模型类型
        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)"的名称会有所不同。有人可以帮我解决这个问题吗?

英文:

Right now I have a small application for calculating statistics with a parallel algorithms.
Now I've got a problem with expanding some part of functionality. I'll try to explain shortly.
App is build on revel framework. One of the actions of "stat" controller takes incoming POST json. Parses it. And generates two channels (goroutines) for tasks and results. All that works like a charm. But I have troubles with models. I wrote code to be able to expand models amount linearly, but for this moment there was only one in work.

And not all of methods are adopted for this expanding.

In some part of code I have this :

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 &quot;noagg&quot;:
				deserializedData = new(models.NoaggModel)
			case &quot;acsi&quot;:
				deserializedData = new(models.AcsiModel)
			}

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

			marshal_error := json.Unmarshal([]byte(cacheData), &amp;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(&quot;some is bad&quot;)
				}

				w.Name, w.Data = chart.Name, countedData
				out &lt;- w
			}
		}
	}

Noagg model and Asci model are implementing the same interface of the "stat" model :

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

But now I have to add some new models with the same interface, but there is code, that I can't expand . I can't remember how to do this..

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 {
		&quot;HOLD&quot; : HOLD,
		&quot;INB&quot;  : INB,
		&quot;AHT&quot;  : AHT,
		&quot;RING&quot; : RING,
		&quot;TALK&quot; : TALK,
		&quot;ACW&quot;  : ACW,
		&quot;OCC&quot;  : OCC,
	}
	countedStat := statCount(model, m[name])
	return countedStat
}

The same methods I need for ASCI model. For AcsiRow instead of NoaggRow. How to make this input params types dynamic or how to make methods common for all models. Only array and names of "map[string]func(......Row)" would differ in this place. Can anyone help me out with this ?

答案1

得分: 1

如果地图中的函数(即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,
        // 在这里映射AcsiModel函数,假设它们被称为ACSIn
        // (您提到名称可能不同,所以我假设它们不会干扰上面的函数):
        "ACSI1": ACSI1,
        "ACSI2": ACSI2,
        "ACSI3": ACSI3,
    }
    countedStat := statCount(model, m[name])
    return countedStat
}

免责声明:这只是一个基于我在帖子中看到的内容的想法。我对Revel一无所知,因此可能会忽略一些由Revel上下文引起的重要细节,这可能会阻止实现此方法。

根据评论更新

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

func HOLD(s StatModel) float64 {
    noagg, ok := s.(NoaggRow) // 从StateModel转换为NoaggRow
    if !ok {
        // 看起来调用者没有将匹配的模型/名称对传递给Count()。
        // 错误处理...
    }
    attr := noagg.AttributeSpecificToNoaggRow
    ...
}

这可能在运行时看起来有些冒险,但如果调用者始终将匹配的模型/名称值对传递给Count()(我假设是这样),类型转换应该是安全的。

英文:

If the functions in the map (that is, HOLD(), INB(), etc) do not need more access to the models than the StatModel interface provides, then your requirement should be possible by changing these functions to receive a StatModel instead of a NoaggRow:

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

Then the AcsiRow functions that you want to add can have the same signature, and statCount and Count can be rewritten as follows:

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 {
		&quot;HOLD&quot; : HOLD,
		&quot;INB&quot;  : INB,
		&quot;AHT&quot;  : AHT,
		&quot;RING&quot; : RING,
		&quot;TALK&quot; : TALK,
		&quot;ACW&quot;  : ACW,
		&quot;OCC&quot;  : OCC,
		// Map AcsiModel functions here, let&#39;s call them ACSIn here
        // (you mentioned that the names would be different, so
        // I assume they don&#39;t get in the way of the functions
        // above):
		&quot;ACSI1&quot;: ACSI1,
		&quot;ACSI2&quot;: ACSI2,
		&quot;ACSI3&quot;: ACSI3,
	}
	countedStat := statCount(model, m[name])
	return countedStat
}

Disclaimer: This is just an idea that is based on what I can see in the post. I know nothing about Revel and maybe I thus might have missed some important detail that is induced by the Revel context that would prevent implementing this approach.

Update based on the comment:

Use type assertions to enable the HOLD, OCC, etc. functions to access struct specific attributes, like so:

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
	...
}

This might look somehow risky at runtime, but if the caller always passes matching pairs of model/name values to Count() (and I assume it does so), the typecast should be safe.

huangapple
  • 本文由 发表于 2016年4月21日 20:07:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/36769125.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定