假设我在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的解决方案(它们是库内部的,并且没有任何意义。它)。
答案 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。如果需要,您必须添加同步。