2015-04-15 14 views
6

Angenommen, ich habe einen Strukturtyp in Go, den ich als Schlüssel in einer Map verwenden möchte, aber ich möchte nicht Go's eingebaute Gleichheitsoperation verwenden. Was ist der beste Weg, um eine solche Karte zu erstellen?Go Karte mit benutzerdefinierten Schlüssel mit benutzerdefinierten Gleichheit?

Für ein konkretes Beispiel, hier ist mein Schlüssel Art und Gleichheit Betrieb:

type Key struct { 
    a *int 
} 

func Equal(x Key, y Key) bool { 
    return *x.a == *y.a 
} 

Wie kann ich eine Karte erstellen, die Equal für Schlüsselvergleich verwendet?

+0

Aber wie würde ich sagen, dass Karte diese Methode verwenden sollte? Schlimmer noch, in meinem echten Code ist das Feld a ein Stück von int, und soweit ich weiß, gibt es keine integrierten Gleichheitsoperationen für Sil- ces. –

+0

Ja, in der FAQ https://golang.org/doc/faq gibt es eine Frage, warum Karten nicht Slices als Schlüssel erlauben und die Antwort ist, dass es keinen eingebauten Gleichheitsoperator gibt. Ich habe vorgeschlagen, was ich für die vernünftigste Lösung in meiner Antwort halte. – evanmcdonnal

Antwort

2

Dies ist in Go nicht möglich. Es gibt keine Überladung von Operatoren oder die Methode "Gleichheit", die Sie überschreiben können (weil Sie nicht von einer gemeinsamen Basisklasse wie in .NET geerbt haben, an die Ihr Beispiel mich erinnert). Diese Antwort enthält weitere Informationen zu Gleichheitsvergleichen, wenn Sie interessiert sind. Is it possible to define equality for named types/structs?

Wie in den Kommentaren erwähnt, wenn Sie etwas wie diese Arbeit machen möchten, würde ich empfehlen, eine Eigenschaft auf dem Objekt als Schlüssel zu verwenden. Sie können die Gleichheit basierend darauf definieren, wie Sie den Wert dieser Eigenschaft festlegen (so wie es eine Prüfsumme der Objektbytes oder etwas sein könnte, wenn Sie nach Elementgleichheit suchen).

6

Gehen hat strict comparable semantics for values used as map keys. Daher können Sie nicht wie in vielen anderen Sprachen eigene Hashcode- und Gleichheitsfunktionen für Map-Schlüssel definieren.

Beachten Sie jedoch die folgende Problemumgehung. Verwenden Sie anstelle der direkten Verwendung der Struct-Instanzen als Schlüssel ein abgeleitetes Attribut der Struktur, das an sich als Schlüssel verwendbar ist und die von Ihnen gewünschte Gleichheits-Semantik aufweist. Oft ist es einfach, einen Integer- oder String-Wert als Hash-Code abzuleiten, der als Identität für eine Instanz dient.

Zum Beispiel:

type Key struct { 
    a *int 
} 

func (k *Key) HashKey() int { 
    return *(*k).a 
} 

k1, k2 := Key{intPtr(1)}, Key{intPtr(2)} 
m := map[int]string{} 
m[k1.HashKey()] = "one" 
m[k2.HashKey()] = "two" 
// m = map[int]string{1:"one", 2:"two"} 
m[k1.HashKey()] // => "one" 

Natürlich ist Unveränderlichkeit ein kritisches Anliegen mit diesem Ansatz. Wenn Sie im obigen Beispiel das Feld a ändern, kann die Instanz nicht mehr als Hash-Schlüssel verwendet werden, da sich ihre Identität geändert hat.

+0

Danke. In meinem echten Code habe ich Scheiben als Schlüssel. Ich schätze, ich muss Hashwerte mit sehr hoher Qualität für 128-Bit-Werte verwenden oder sie zu Strings "hacken". –

+0

@ ArchD.Robison: sicher, das eingebaute ['crypto/md5'-Paket] (http://golang.org/pkg/crypto/md5/) könnte dafür hilfreich sein, oder sogar eine einfache String-Darstellung des Slices via ['fmt.Sprintf ("% v ", slc)'] (http://golang.org/pkg/fmt/#Sprintf). – maerics

Verwandte Themen