map[任务]int64其中任务是一个接口

huangapple go评论78阅读模式
英文:

map[Task]int64 where Task is an interface

问题

让我们假设我在一个Go库中定义了以下接口:

type Task interface {
    Do() error
}

func Register(task Task) { ... }

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

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

我的初始想法是将这个关联存储为map[Task]int64。这似乎工作得很好,但有人告诉我,如果实现Task的对象不可比较相等(例如,包含mapstruct),这种方法会出错。我仍然需要检查这是否正确。

我打算尝试使用struct { task Task; id int64 }的切片,然后只需对其进行迭代,但这仍然需要可比较相等的Task实例。而且据我所知,Go语言中没有身份比较。

我如何实现从Task实例到其ID的稳健映射?

编辑:到目前为止,提出的两种解决方案都可以工作,但它们的缺点是每个Task实现都必须包含一些重复的代码来处理ID。我可以在一个TaskBase的struct中提供该代码,然后进行嵌入,但理想情况下,我希望找到一种不需要实现甚至了解ID的解决方案(它们对库来说是内部的,对外部没有意义)。

英文:

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

得分: 4

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())
}

英文:

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\n", t1.ID())
	fmt.Printf("%x\n", 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.

huangapple
  • 本文由 发表于 2012年11月23日 03:44:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/13519152.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定