Golang中的身份比较?

I've been trying to build a set of structs that have a base struct as their foundation and variants built on top of that. I've found, however, that there doesn't seem to be a way for the struct to identify itself when the common code is in the base struct. How should I be doing this?

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
", b1.IsMe(b1))
    fmt.Printf("b1.IsMe(b2): %v
", b1.IsMe(b2))
    fmt.Printf("b2.IsMe(b1): %v
", b2.IsMe(b1)) // Wrong result!
    fmt.Printf("b2.IsMe(b2): %v
", b2.IsMe(b2)) // Wrong result!
}
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
", b1.IsMe(b1))
    fmt.Printf("b1.IsMe(b2): %v
", b1.IsMe(b2))
    fmt.Printf("b2.IsMe(b1): %v
", b2.IsMe(b1))
    fmt.Printf("b2.IsMe(b2): %v
", b2.IsMe(b2))
}

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

If you really want to do it the fake inheritance way then you can certainly do it the way you did it but it really only works with unsafe or reflect because the language is not designed for what you want to do.

Your problem starts with where x.IsMe comes from when using embedding. When you write

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

the method IsMe is actually associated and bound to Block instead of Block2. So calling IsMe on an instance of Block2 is really only calling it on Block, in detail:

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

Both methods have the same address. This shows that even though b2 has the method IsMe, that method is only propagated from Block to the outside of Block2 and not inherited. This in turn means that you are always running effectively this code:

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

which obviously cannot work since you are comparing two completely different instances.

What you really should do is to use some function outside of your embedding chain to decide equality. Example (On Play):

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

This actually compares the right instances.