golang中的身份比较?

时间:2016-07-26 23:23:14

标签: go

我一直在尝试构建一组结构,这些结构以基础结构为基础,并在其基础上构建变体。但是,我发现,当公共代码位于基本结构中时,结构似乎不是一种识别自身的方法。我该怎么做?

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!
}

2 个答案:

答案 0 :(得分:2)

如果你真的想以伪造的继承方式去做,那么你当然可以按照你的方式去做,但它实际上只适用于unsafereflect,因为该语言不是为什么设计的你想做什么。

您的问题始于使用嵌入时来自x.IsMe的位置。当你写

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

方法IsMe实际上已关联并绑定到Block而不是Block2。因此,在IsMe的实例上调用Block2实际上只是在Block上调用它,详细信息:

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

两种方法都具有相同的地址。这表明即使b2具有方法IsMe,该方法也只会从Block传播到Block2之外,不会继承。这反过来意味着您始终有效地运行此代码:

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

显然无法正常工作,因为您要比较两个完全不同的实例。

你真正应该做的是使用嵌入链之外的一些函数来决定相等性。示例(On Play):

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

这实际上比较了正确的实例。

答案 1 :(得分: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