dongni9825 2012-11-22 19:44
浏览 39
已采纳

map [Task] int64其中Task是一个接口

Let's say I define the following interface in a Go library:

type Task interface {
    Do() error
}

func Register(task Task) { ... }

func GetId(task Task) int64 { ... }

In Register(), the library associates a unique int64 with each task instance. GetId() must return the identifier for the given task.

My initial idea was to store the association as a map[Task]int64. This seems to work fine, but I was told that it would break if an object implementing Task was not equality-comparable (for example, a struct containing a map). I still need to check if this is true.

I was going to try and use a slice of struct { task Task; id int64 } instead and just iterate over it, but that would still require equality comparable Task instances. And AFAIU there is no identity comparison in Go.

How can I have a robust mapping from Task instances to their ID?

EDIT: Both solutions proposed so far work, but they have the disadvantage that every Task implementation has to include some repetitive code to handle the IDs. I could provide that code in a TaskBase struct that could be embedded, but ideally I would prefer a solution that doesn't require implementations to even know about the IDs (they are internal to the library and have no meaning outside of it).

  • 写回答

1条回答 默认 最新

  • dsfdsf21312 2012-11-22 20:42
    关注

    A more complete example: http://play.golang.org/p/1RzDiw7F9t

    package main
    
    import (
        "fmt"
        "math/rand"
    )
    
    type Task interface {
        Do() error
        ID() int64
    }
    
    type XTask struct {
        id int64
        // other stuff
    }
    
    func NewXTask( /*task parameters...*/) *XTask {
        t := &XTask{ /*initialize members*/}
        t.id = Register(t)
        // possibly more initialization...
        return t
    }
    
    func (t *XTask) Do() error  { return nil }  // stub
    func (t *XTask) ID() int64  { return t.id }
    
    var taskRegistry = map[int64]Task{}
    
    func Register(t Task) int64 {
        var id int64
        for {
            id = rand.Int63()
            if _, exists := taskRegistry[id]; !exists {
                break
            }
        }
        taskRegistry[id] = t
        return id
    }
    
    func main() {
        t1 := NewXTask()
        t2 := NewXTask()
        fmt.Printf("%x
    ", t1.ID())
        fmt.Printf("%x
    ", t2.ID())
    }
    

    I used an ID method as Daniel suggested, and I turned the map backwards from the way you had it. This is because the Task objects know their own ID, so a map from Task to ID is not needed. A map from ID to task however, is useful for guaranteeing uniqueness. It might come in handy some other time if you find yourself with only an ID and you need the corresponding Task object.

    Also note this example is not goroutine-safe. If you need that you will have to add synchronization.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?