3

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

type Task interface {
    Do() error
}

func Register(task Task) { ... }

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

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

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

我打算尝试使用一片 ofstruct { task Task; id int64 }代替并对其进行迭代,但这仍然需要相等的可比较Task实例。而 AFAIU 在 Go 中没有身份比较。

我怎样才能拥有从Task实例到它们的 ID 的强大映射?

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

4

1 回答 1

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 安全的。如果需要,您必须添加同步。

于 2012-11-22T20:42:20.120 回答