3

Goライブラリで次のインターフェイスを定義するとします。

type Task interface {
    Do() error
}

func Register(task Task) { ... }

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

Register()、ライブラリは一意int64を各タスクインスタンスに関連付けます。GetId()指定されたタスクの識別子を返す必要があります。

私の最初のアイデアは、関連付けをとして保存することでしたmap[Task]int64。これは問題なく機能しているように見えますが、実装しているオブジェクトTaskが同等に比較できない場合(たとえば、をstruct含むmap)、機能しなくなると言われました。私はまだこれが本当かどうかを確認する必要があります。

代わりにスライスを試して使用し、struct { task Task; id int64 }それを繰り返し処理するつもりでしたが、それでも同等の同等のTaskインスタンスが必要になります。そして、AFAIUにはGoにアイデンティティの比較はありません。

TaskインスタンスからIDへの堅牢なマッピングを作成するにはどうすればよいですか?

編集:これまでに提案された両方のソリューションは機能しますが、すべてのタスク実装にIDを処理するための反復コードを含める必要があるという欠点があります。埋め込むことができるTaskBaseでそのコードを提供することもstructできますが、理想的には、IDについてさえ知るための実装を必要としないソリューションを好みます(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())
}

ダニエルが提案したようにIDメソッドを使用し、マップをあなたが持っていた方法から逆にしました。これは、Task オブジェクトが独自の ID を認識しているためです。そのため、Task から ID へのマップは必要ありません。ただし、ID からタスクへのマップは、一意性を保証するのに役立ちます。ID だけを持っていて、対応する Task オブジェクトが必要な場合は、別の機会に役立つかもしれません。

また、この例はゴルーチンセーフではないことに注意してください。必要な場合は、同期を追加する必要があります。

于 2012-11-22T20:42:20.120 に答える