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

时间:2012-11-22 19:44:56

标签: map go identity

假设我在Go库中定义了以下接口:

type Task interface {
    Do() error
}

func Register(task Task) { ... }

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

Register()中,库将唯一int64与每个任务实例相关联。 GetId()必须返回给定任务的标识符。

我最初的想法是将关联存储为map[Task]int64。这似乎工作正常,但有人告诉我,如果实现Task的对象不具有可比性(例如,包含struct的{​​{1}}),它将会中断。我仍然需要检查这是否属实。

我打算尝试使用map切片而只是迭代它,但这仍然需要与struct { task Task; id int64 }个实例相当的平等。和AFAIU在Go中没有身份比较。

如何从Task个实例到其ID进行强大的映射?

编辑:到目前为止提出的两种解决方案都有效,但它们的缺点是每个Task实现都必须包含一些重复的代码来处理ID。我可以在可以嵌入的TaskBase Task中提供该代码,但理想情况下我更喜欢一种不需要实现甚至知道ID的解决方案(它们是库内部的,并且没有任何意义。它)。

1 个答案:

答案 0 :(得分:4)

更完整的示例: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\n", t1.ID())
    fmt.Printf("%x\n", t2.ID())
}

我使用了Daniel建议的ID方法,然后我从你拥有它的方式向后转动了地图。这是因为Task对象知道自己的ID,因此不需要从Task到ID的映射。但是,从ID到任务的映射对于保证唯一性很有用。如果您发现自己只有一个ID并且需要相应的Task对象,那么它可能会派上用场。

另请注意,此示例不是goroutine-safe。如果需要,您必须添加同步。