Map go中地图的类型转换

Map go中地图的类型转换,map,type-conversion,go,Map,Type Conversion,Go,给定的typedef为:“type ID int” 是否可以将map[ID]int转换为map[int]int 我试过: map[int]int(m) 以及 m.(map[int]int) 这两种方法似乎都不管用: 有什么建议吗 编辑更多细节,因为有几个人问过 我想做的是在联赛中得分 有一群“团队”,每个团队都有一些统计数据。每一次统计,得分最高得10分,第二名得9分,以此类推 我将其建模为: // Each team's statistics: type StatLine map[St

给定的typedef为:“type ID int”

是否可以将map[ID]int转换为map[int]int

我试过:

map[int]int(m)
以及

m.(map[int]int)
这两种方法似乎都不管用:

有什么建议吗


编辑更多细节,因为有几个人问过

我想做的是在联赛中得分

有一群“团队”,每个团队都有一些统计数据。每一次统计,得分最高得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恰好是int,因此我很好奇是否可以只编写score(s map[int]int)并进行类型转换。然而,SteveMcQwark清楚地说明了为什么这可能是个坏主意

我认为仿制药可以解决这个问题,但我知道它们不会马上出现。还有其他想法吗


谢谢

转换规则是表达性和可维护性之间的折衷。无论何时在两种类型之间进行转换,您都在打赌这些类型在未来将保持代表性和逻辑上的兼容性。类型系统的目标之一是最小化依赖于此兼容性的扩展。另一方面,能够定义可以对同一数据进行操作的多个方法集非常有用,转换允许您根据需要选择适当的方法集对现有数据进行操作。您只能在可以合法地交换其他相同类型的方法集的情况下进行转换,这不包括您所询问的情况


了解你想做什么,而不是如何去做,可能会很有用。我的意思是,如果您只需要只读访问它,您可以将
map[ID]int
包装在
func(int)(int,bool)
中,或者您可以使用
接口{Get(int)(int,bool);Set(int,int);Delete(int)}
,但这很可能是不必要的

将TeamID和PlayerID分为两种类型可能过于工程化了。如果两个都使用相同的类型,比如ScoreableID,问题就会消失。在大多数情况下,变量名、函数名或程序上下文可以清楚地表明某个对象是玩家还是团队。注释在任何剩余的模棱两可的代码中都是合适的。

如果你真的想在Go中做泛型,你需要一个接口。该接口将由两种类型实现,一种用于团队,另一种用于玩家。score函数将此接口类型的对象作为参数,并在不知道它是与团队还是与玩家一起工作的情况下实现通用评分逻辑。这是概述。以下是一些细节:

接口的方法集正是score函数所需的函数。让我们从两种可能需要的方法开始

type scoreable interface {
    stats(scID) StatLine  // get statLine for ID
    score(scID, int)      // set score for ID
}
和一个通用的可记分ID类型

type scID int
可以实现此接口的类型不是TeamID和PlayerID,而是包含它们的映射的类型。此外,每种类型都需要地图、基准线和分数地图。结构适用于以下情况:

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执行相同的操作,定义一个类似的结构并添加这两个方法

编写一次score函数。这样开始:

func score(s scoreable) {
    for
ts := &teamScores{
    stats:  ...your existing map[TeamID]Statline,
    scores: make(map[TeamID]int),
}
哎呀,我们需要一些迭代的方法。一个权宜之计是获得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
    }
}
请注意,该函数采用的接口类型是scoredable,而不是指向像*scoredable这样的接口的指针。接口可以保存指针类型*teamScores。没有指向接口的附加指针是合适的

最后,要调用泛型函数,我们需要teamScores类型的对象。你可能已经有了联赛统计数据,但可能还没有创建分数地图。您可以像这样一次完成所有这些:

func score(s scoreable) {
    for
ts := &teamScores{
    stats:  ...your existing map[TeamID]Statline,
    scores: make(map[TeamID]int),
}
电话:


团队得分将以ts.scores为单位。

我没有回答,而是问:你想解决什么问题?可能有一种“走”的方式;-)嘿这是一个令人敬畏的答案。我真正想要的是Java泛型提供的东西:“compute(m map[T]SomeStruct)map[T]int”。。。也就是说,我不关心函数内部的map键(除了将其用作键),但我希望方法的输入和输出是相同的类型。