给出的类型为:"type int“
能否将mapIDint转换为mapintint?
我试过:
map[int]int(m)
以及
m.(map[int]int)
两者似乎都不起作用:http://play.golang.org/p/oPzkUcgyaR
有什么建议吗?
编辑更多细节,因为有几个人问。
我想做的是在联赛中得分。
这里有一群“团队”,每个队都有一些统计数据。对于每一个统计,你得到10分,因为你是最高的得分,9分第二等等。
我把这个建模为:
// Each team's statistics:
type StatLine map[StatID]float64
// The whole league:
map[TeamID]StatLine
// And I want to score that whole league with:
func score(s map[TeamID]StatLine) map[TeamID]int
// Only, is't also handy to score individual players:
func score(s map[PlayerID]StatLine) map[PlayerID]int
最好不要写score()两次(因为这是相同的逻辑)或者复制整个地图。
碰巧PlayerID和TeamID是It,所以我很好奇我是否能写分数(S mapintint)并进行类型转换。然而,SteveMcQwark清楚地说明了为什么这可能是个坏主意。
我认为仿制药可以解决这个问题,但我知道它们不会马上出现。还有其他想法吗?
谢谢!
发布于 2012-05-29 18:31:16
如果您真的想在Go中使用泛型,则需要一个接口。此接口将由两种类型实现,一种用于团队,另一种用于球员。得分函数将以该接口类型的对象作为参数,并在不知道是否与团队或球员一起工作的情况下实现常见的得分逻辑。这就是概述。以下是一些细节:
接口的方法集就是评分函数所需要的函数。让我们从两种方法开始,
type scoreable interface {
stats(scID) StatLine // get statLine for ID
score(scID, int) // set score for ID
}
以及通用的可记分ID类型,
type scID int
可以实现此接口的类型不是TeamID和PlayerID,而是保存它们的映射的类型。此外,这些类型中的每一种都需要两个映射、StatLine和分数映射。此结构适用于以下内容:
type teamScores struct {
stats map[TeamID]StatLine
scores map[TeamID]int
}
实行计分制,
func (s *teamScores) stats(id scID) StatLine {
return s.stats[TeamID(id)]
}
func (s *teamScores) score(id scID, sc int) {
s.scores[TeamID(id)] = sc
}
等等,你可能会说。将scID转换为TeamID的类型。这安全吗?我们是否也应该采用低成本的方法--甚至连TeamID都没有?好吧,只要这些方法被合理使用,就安全了。struct teamScores将TeamID映射与另一个TeamID映射关联起来。我们即将编写的泛型函数评分将此结构作为一个参数,从而给出正确的关联。它不可能混淆TeamID和PlayerID。这是有价值的,在一个足够大的程序中可以证明这种技术是合理的。
对PlayerID也这样做,定义一个类似的结构并添加这两个方法。
写一次分数函数。从这样开始:
func score(s scoreable) {
for
噢,我们需要一些方法来迭代。一个权宜之计的解决方案是获得一个ID列表。让我们添加这个方法:
type scoreable interface {
ids() []scID // get list of all IDs
stats(scID) StatLine // get statLine for ID
score(scID, int) // set score for ID
}
以及teamScores的实现:
func (s *teamScores) ids() (a []scID) {
for tid := range s.stats {
a = append(a, scID(tid))
}
return
}
我们刚才说到哪了?
func score(s scoreable) {
// lets say we need some intermediate value
sum := make(map[scID]float64)
// for each id for which we have a statLine,
for _, id := range s.ids() { // note method call
// get the statLine
stats := s.stats() // method call
// compute intermediate value
sum[id] = 0.
for _, statValue := range stats {
sum[id] += statValue
}
}
// now compute the final scores
for id, s := range sum {
score := int(s) // stub computation
s.score(id, score) // method call
}
}
注意,该函数采用接口类型scoreable,而不是指向诸如*scoreable这样的接口的指针。接口可以保存指针类型*teamScores。没有其他指向接口的指针是合适的。
最后,要调用泛型函数,我们需要一个teamScores类型的对象。你可能已经有联盟的统计数据,但可能还没有创建得分图。你可以同时这样做:
ts := &teamScores{
stats: ...your existing map[TeamID]Statline,
scores: make(map[TeamID]int),
}
打电话:
score(ts)
球队的分数将在ts.scores上。
发布于 2012-05-28 20:13:48
转换规则是表达性和可维护性之间的权衡。无论何时在两种类型之间进行转换,您都在赌这些类型在将来将保持代表性和逻辑兼容性。类型系统的目标之一是将依赖于这种兼容性的扩展降到最低。另一方面,能够定义可以对相同数据进行操作的多个方法集是非常有用的,转换允许您根据需要选择对现有数据进行操作的适当方法集。只有在可以合法地交换其他相同类型的方法集的情况下,才能进行转换,这就排除了所询问的情况。
知道你想做什么也许会有帮助,而不是你想如何去做。我的意思是,如果只需要只读访问,就可以将map[ID]int
封装在func(int)(int, bool)
中,也可以使用interface { Get(int)(int, bool); Set(int, int); Delete(int) }
,但这很有可能是不必要的。
发布于 2012-05-29 16:32:27
采用单独的TeamID和PlayerID类型可能是过度工程。如果您在这两种情况下都使用相同的类型,比如ScoreableID,问题就会消失。在大多数情况下,变量名称、函数名或程序上下文将清楚地表明某物是球员还是团队。在任何剩余的模棱两可的代码中,注释都是适当的。
https://stackoverflow.com/questions/10789001
复制相似问题