2016-05-20 4 views
0

Wie ich es verstehe, kann ich in Go keine Gleichheit für benutzerdefinierte Typen definieren. Also, was wäre die idiomatische Art der Berechnung der Anzahl von verschiedenen Objekten eines benutzerdefinierten Typs (möglicherweise rekursiv definiert). Hier ist ein Beispiel für die Art von Dingen, die ich versuche zu tun.Idiomatische Methode zum Zählen der Anzahl von unterschiedlichen Objekten des rekursiv definierten benutzerdefinierten Typs

package main 

import "fmt" 

type tree struct { 
    left *tree 
    right *tree 
} 

func shapeOf(a tree) string { 
    temp := "{" 
    if a.left != nil { 
     temp += shapeOf(*(a.left)) 
    } 
    temp += "}{" 
    if a.right != nil { 
     temp += shapeOf(*(a.right)) 
    } 
    temp += "}" 
    return temp; 
} 

func main() { 
    a := tree{nil, nil} 
    b := tree{nil, &a} 

    c := tree{nil, nil} 
    d := tree{nil, &c} 

    e := tree{nil, nil} 
    f := tree{&e, nil} 

    s := make(map[string]bool) 

    s[shapeOf(b)] = true 
    s[shapeOf(d)] = true 
    s[shapeOf(f)] = true 
    fmt.Println(len(s)) // As required, prints 2 because the first two trees have the same shape 
} 

Es funktioniert, aber die Verwendung von Strings ist extrem hässlich und wahrscheinlich auch ineffizient. Offensichtlich kann ich schreibe einfach eine rekursive Methode zu sagen, wenn zwei Bäume gleich sind - so etwas wie

func areEqual(a, b tree) bool 

aber das würde mich nicht ermöglichen Bäume zu verwenden, wie Mapkeys. Was ist der idiomatische Weg, um so etwas zu tun?

+2

Wenn Sie ein komplexes Objekt zu einem Schlüssel einer kartenähnlichen Struktur machen, benötigen Sie * * eine Hash-Funktion und eine Gleichheitsfunktion. Go stellt das nicht bereit, aber es gibt keine Möglichkeit, nur eine Funktion dafür zu schreiben. Wenn Sie jedoch etwas idiomatischer/effizienter sein wollen, dann würde ich vorschlagen, [] byte oder bytes.Buffer anstelle von Verkettungen zu verwenden. –

Antwort

1

Sie können die Gleichheit für benutzerdefinierte Typen nicht definieren, da sie bereits von go definiert sind. Grundsätzlich ist alles, was es zu wissen gibt, im Abschnitt comparable erklärt.

Kurzgeschichte: Zwei Strukturwerte können verglichen werden, wenn ihre Felder verglichen werden können (keine Scheibe, Karte oder Funktion). Und dasselbe gilt für die Gleichheit: Zwei Strukturen sind gleich, wenn ihre Felder gleich sind. In Ihrem Fall besteht das Problem darin, dass Golang zum Vergleichen von Zeigern die Speicheradressen vergleicht, nicht die Struktur, auf die sie zeigen.

Also ist es möglich, unterschiedliche Werte einer bestimmten Struktur zu zählen? Ja, wenn die Struktur keine verschachtelte Schicht, Karte, Funktion oder Zeiger enthält. Für rekursive Typen, das ist nicht möglich, weil Sie nicht so etwas wie dies definieren:

type tree struct { 
    left tree 
    right tree 
} 

Der idiomatische Weg, um die Gleichheit der rekursiven Arten von Tests ist reflect.DeepEqual(t1, t2 interface{}) zu verwenden, wie es Indirekt folgt. Diese Methode ist jedoch ineffizient, da sie eine starke Reflexion verwendet. In Ihrem Fall glaube ich nicht, dass es eine saubere und elegante Lösung gibt, um zu bekommen, was Sie wollen.

+0

Danke. Das ist die Bestätigung, die ich brauchte. Mir war 'reflect.DeepEqual' nicht bewusst. Wenn es auch ein 'DeepHash' gibt, könnte ich meine eigene Hashtable-Implementierung für beliebige Typen schreiben. –

Verwandte Themen