我一直在尝试构建一组结构,这些结构以基础结构为基础,并在其基础上构建变体。但是,我发现,当公共代码位于基本结构中时,结构似乎不是一种识别自身的方法。我该怎么做?
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 :(得分:2)
如果你真的想以伪造的继承方式去做,那么你当然可以按照你的方式去做,但它实际上只适用于unsafe
或reflect
,因为该语言不是为什么设计的你想做什么。
您的问题始于使用嵌入时来自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))
}