有两种结构,
Foo
有Clone()
方法
Bar
继承自Foo
package main
import "fmt"
type IF interface {
Clone() IF
}
type Foo struct {
i int
}
func (this *Foo) Clone() IF {
c := *this
return &c
}
type Bar struct {
Foo
}
func main() {
t := &Bar{}
c := t.Clone()
fmt.Printf(`%T `, t)
fmt.Printf(`%T `, c)
}
https://play.golang.org/p/pFn348aydW
输出
*main.Bar *main.Foo
但我希望克隆Bar
,而不是Foo
我必须将Bar.Clone()
与Foo.Clone()
func (this *Bar) Clone() IF {
c := *this
return &c
}
https://play.golang.org/p/J6jT_0f1WW
现在输出是我想要的
*main.Bar *main.Bar
如果我会写很多像Bar
这样的结构,我就不会写很多Clone()
,我能做什么?
最好不要使用反射
答案 0 :(得分:3)
Go没有继承,这是组合,而不是继承,这就是你感到沮丧的原因。 Bar并不从Foo继承,它嵌入了Foo,这是非常不同的。嵌入时,嵌入式方法作用于嵌入式结构,而不是包装器,所以是的,你是正确的,如果你想要返回一个Bar,你必须添加一个Clone()吧。
可能最好退后一步,考虑一下你为什么要嵌入Foo - 不要试图像基类那样使用Foo,把它想象成一个代码模块你#&# 39;重新导入(自包含,仅指Foo中的数据,而不是Bar中的数据)。所以很明显这只是一个玩具示例,但要扩展它以说明Foo的作用:
type Foo struct {
i int
}
func (f *Foo) String() string {
if f.i > 0 {
return fmt.Sprintf("val:%d", f.i)
}
return ""
}
type Bar struct {
Foo
}
// Bar conforms to Stringer by virtue of embedding Foo
// using the Foo data stored in i
type Stringer interface {
String() string
}
func Print(b Stringer) {
fmt.Printf("%s", b)
}
func main() {
b := &Bar{}
Print(b) // Outputs empty string
b.i = 4
Print(b) // Outputs val:4
}
https://play.golang.org/p/tNWPVw79aa
所以你可以使用Foo方法,但它们只应该与Foo结构的内容相关,你应该把所有内容保存在Bar中,直到你确定你因为某种原因需要Foo,然后将其分解出来 - Go将指导您实现最小的复杂性,并且不支持继承。
在支持继承的语言中,您可以通过使用抽象基类工厂等生成一个可爱的类分类来开始您的设计过程。首先,您要考虑附加到它或对其执行操作的数据和行为。
答案 1 :(得分:0)
Go不提供继承而不是Go提供组合。
<强>组合物强>:
在计算机科学中,对象组合是一种将简单对象或数据类型组合成更复杂对象的方法。
<强>继承强>:
在面向对象的编程中,继承是指对象或类基于另一个对象或类,使用相同的实现或指定新的实现来维持相同的行为。
可以将多个结构组合成单个组合,但每个方法都无法访问外部结构或其他组合结构。外部结构也可以访问内部结构。您应该将外(非父)结构视为内(非子)结构的包装。
嵌入与子类化不同的重要方法。当我们嵌入一个类型时,该类型的方法成为外部类型的方法,但是当它们被调用时,方法的接收者是内部类型,而不是外部类型。
由于您尝试做的事情是不可能的,请查看与您的snippet大致相同的,但设计更加明确和惯用(我相信它可以为您提供正确的实施方案):
type IF interface {
DoSomething()
}
type Foo struct {
i int
}
func (f *Foo) DoSomething() {}
type Cloner struct {
*Foo
}
func (this *Cloner) Clone() IF {
c := *this.Foo
return &c
}
func main() {
f := new(Foo)
t := &Cloner{f}
c := t.Clone()
fmt.Printf("%T \n", t)
fmt.Printf("%p \n", f)
fmt.Printf("%p ", c)
}