2016-07-26 6 views
2

Ich habe versucht, eine Reihe von Strukturen zu erstellen, die eine Basisstruktur als ihre Grundlage und Varianten darauf gebaut haben. Ich habe jedoch herausgefunden, dass es keine Möglichkeit für die Struktur gibt, sich zu identifizieren, wenn sich der gemeinsame Code in der Basisstruktur befindet. Wie soll ich das machen?Identitätsvergleich in Golang?

package main 

import (
    "fmt" 
) 

type Base interface { 
    IsMe(other Base) bool 
} 

type Block struct { 
} 

func (b *Block) IsMe(other Base) bool { 
    return b == other 
} 

type Block2 struct { 
    Block 
} 

func main() { 
    b1 := &Block{} 
    b2 := &Block2{} 
    fmt.Printf("b1.IsMe(b1): %v\n", b1.IsMe(b1)) 
    fmt.Printf("b1.IsMe(b2): %v\n", b1.IsMe(b2)) 
    fmt.Printf("b2.IsMe(b1): %v\n", b2.IsMe(b1)) // Wrong result! 
    fmt.Printf("b2.IsMe(b2): %v\n", b2.IsMe(b2)) // Wrong result! 
} 
+0

Nur klar sein, ich weiß, dass ich dies hinzufügen: func (b * Block2) IsMe (andere Basis) bool { return b == andere } und ich werde dann das richtige Ergebnis bekommen. .. Ich möchte jedoch nicht für jede Unterstruktur den gleichen Kode für die Kachelplatte schreiben. –

+0

http://stackoverflow.com/questions/35546054/golang-equivalent-of-is-operator-in-python – IanAuld

+1

Dank @IanAuld, aber dieser Link scheint nicht relevant für dieses spezielle Problem. Beachten Sie, dass eine Schnittstelle beteiligt ist. –

Antwort

1
package main 

import (
    "fmt" 
    "reflect" 
) 

type Base interface { 
    IsMe(other Base) bool 
} 

type Block struct { 
    _ [1]byte // size of struct must be greater than zero 
} 

func (b *Block) IsMe(other Base) bool { 
    x := reflect.ValueOf(b) 
    y := reflect.ValueOf(other) 
    return x.Pointer() == y.Pointer() 
} 

type Block2 struct { 
    Block // "parent" needs to be first element 
} 

func main() { 
    b1 := &Block{} 
    b2 := &Block2{} 
    fmt.Printf("b1.IsMe(b1): %v\n", b1.IsMe(b1)) 
    fmt.Printf("b1.IsMe(b2): %v\n", b1.IsMe(b2)) 
    fmt.Printf("b2.IsMe(b1): %v\n", b2.IsMe(b1)) 
    fmt.Printf("b2.IsMe(b2): %v\n", b2.IsMe(b2)) 
} 

https://play.golang.org/p/Dx0Ze3euFY

+0

Danke. Das hat den Trick gemacht.Ich habe die Verwendung des unsicheren Pakets beseitigt, indem ich den IsMe() - Inhalt folgendermaßen geändert habe: return reflect.ValueOf (Base (b)). Pointer() == reflect.ValueOf (andere) .Pointer() –

+0

@RichardWilkes: Ja. Siehe aktualisierte Antwort. –

2

Wenn Sie es wirklich die falsche Vererbung Weise tun wollen, dann können Sie sicher es so, wie du es getan hast, aber es funktioniert wirklich nur mit unsafe oder reflect weil die Sprache ist nicht für das, was Sie tun möchten.

Ihr Problem beginnt mit, woher x.IsMe stammt, wenn Sie Einbettung verwenden. Wenn Sie

type Block struct {} 
func (b *Block) IsMe(other Base) bool { return b == other } 
type Block2 struct { Block } 

das Verfahren IsMe schreiben tatsächlich zugeordnet und zu Block statt Block2 gebunden. So ruft IsMe auf einer Instanz von Block2 ist wirklich nur auf Block, im Detail Aufruf:

b2 := Block2{} 
fmt.Println(b2.IsMe)  // 0x21560 
fmt.Println(b2.Block.IsMe) // 0x21560 

Beide Methoden haben die gleiche Adresse. Dies zeigt, dass, obwohl b2 das Verfahren IsMe hat, dieses Verfahren nur von Block auf die Außenseite Block2 und nicht vererbt weitergegeben wird. Dies wiederum bedeutet, dass Sie immer effektiv diesen Code ausgeführt werden:

b1 := Block{} 
b2 := Block2{} 
b2_embedded_block := b2.Block 
b2_embedded_block.IsMe(b2) 
b2_embedded_block.IsMe(b1) 
// ... 

, die offensichtlich nicht arbeiten können, da Sie zwei völlig verschiedene Instanzen vergleichen.

Was Sie wirklich tun sollten, ist eine Funktion außerhalb Ihrer Einbettungskette zu verwenden, um Gleichheit zu entscheiden. Beispiel (On Play):

func IsEq(a,b Base) bool { 
    return a == b 
} 

Dies ist eigentlich die richtigen Instanzen vergleicht.

+0

Das war, was ich tun wollte, aber da es das Objekt selbst ist, das sich mit einer anderswo gespeicherten Schnittstelle vergleichen muss, konnte ich keinen sauberen Weg finden, es zu funktionieren, ohne Code in jede Variation zu replizieren. –

+0

Ihr Beispiel ist wahrscheinlich zu abstrahieren, um das zugrunde liegende Problem hervorzuheben, aber die Tatsache, dass Sie keine saubere Lösung finden konnten, kann darauf hinweisen, dass Ihr ursprünglicher Ansatz Fehler aufweist. Die Art und Weise, wie Sie es jetzt tun (mit reflect), ist ein Workaround, keine Lösung. – nemo