Inheritance 戈朗与继承

Inheritance 戈朗与继承,inheritance,go,idioms,Inheritance,Go,Idioms,我想在我的库中提供一个基本结构,其中包含可以“扩展”的方法 此基本结构的方法依赖于扩展结构中的方法。 这在Go中不可能直接实现,因为结构方法只能访问结构本身的字段,而不能访问父结构 关键是要有我不必在每个扩展类中重复的功能。 我想出了这个模式,效果很好, 但由于它的周期性结构,看起来相当复杂 我从未在其他Go代码中找到类似的代码。 这很不正常吗? 我可以采取什么不同的方法 type MyInterface interface { SomeMethod(string) OtherMetho

我想在我的库中提供一个基本结构,其中包含可以“扩展”的方法

此基本结构的方法依赖于扩展结构中的方法。 这在Go中不可能直接实现,因为结构方法只能访问结构本身的字段,而不能访问父结构

关键是要有我不必在每个扩展类中重复的功能。

我想出了这个模式,效果很好, 但由于它的周期性结构,看起来相当复杂

我从未在其他Go代码中找到类似的代码。 这很不正常吗? 我可以采取什么不同的方法

type MyInterface interface {
  SomeMethod(string)
  OtherMethod(string)
}

type Base struct{
  B MyInterface
}

func (b *Base) SomeMethod(x string) {
  b.B.OtherMethod(x)
}

type Extender struct {
  Base
}

func (b *Extender) OtherMethod(x string) {
  // Do something...
}

func NewExtender() *Extender { 
  e := Extender{}
  e.Base.B = &e
  return &e
}

正如人们评论中提到的,围棋鼓励组合而不是继承

要解决有关减少代码重复的问题,您可能希望使用

使用上面链接的示例,您可以从非常狭窄的界面开始,这些界面只做几件事:

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}
然后,您可以将接口组合到另一个接口中:

// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
    Reader
    Writer
}
它同样适用于结构,您可以在另一个结构中组合实现读写器的结构:

type MyReader struct {}
func (r *MyReader) Read(p []byte) (n int, err error) {
    // Implements Reader interface.
}
type MyWriter struct {}
func (w *MyWriter) Write(p []byte) (n int, err error) {
    // Implements Writer interface.
}

// MyReadWriter stores pointers to a MyReader and a MyWriter.
// It implements ReadWriter.
type MyReadWriter struct {
    *MyReader
    *MyWriter
}
基本上,任何实现
读卡器
写卡器
的东西都可以通过将它们组合在一个结构中来重用,并且外部结构将自动实现
读卡器
接口

这基本上是在做,而且对于测试也非常有用

上面的结构代码示例:

func (rw *MyReadWriter) DoCrazyStuff() {
    data := []byte{}
    // Do stuff...
    rw.Read(data)
    rw.Write(data)
    // You get the idea...
}

func main() {
    rw := &MyReadWriter{&MyReader{}, &MyWriter{}}
    rw.DoCrazyStuff()
}
需要指出的一点是,
MyReadWriter
struct现在既可以充当
Reader
又可以充当
Writer
,这与其他语言的组合范式略有不同。这就是为什么在
DoCrazyStuff()
中我们使用
rw.Read(数据)
而不是
rw.Reader.Read(数据)


更新:修复了错误的示例。

很抱歉让您失望,但您提出的问题是错误的。当我开始编写Go代码时,我也遇到了类似的问题

您不能简单地采用类层次结构并将其转换为Go代码,至少不能获得令人满意的结果。在围棋中通常有一种非常优雅和简单的方法来解决这些问题,但要发现它们,你需要像习惯一样有点不同的想法


不幸的是,您的问题没有说明您试图解决的问题。您刚才描述了您希望如何解决它。因此,我有点不愿意给出一个一般性的答案,因为它不会导致习惯的Go代码。如果你对这个答案感到失望,我可以理解,但在我看来,这是你能得到的最有价值的答案:)

很难从一个通用示例中看出你在做什么,但这不是惯用的Go代码。通常,您需要避免考虑通过类和继承来解决问题。充分利用组合,记住并非所有内容都需要由接口表示的结构——有时功能就是您所需要的全部。重新设计您的解决方案。围棋没有继承权。试图用围棋提供的东西重塑继承很可能会失败;你问这是否是一个合适的方法,如果不是,你可以做些什么使它更好。冒着看起来像个怪人的风险,我认为你的问题很好。话虽如此,我上面的两位评论员说得很对。你的代码示例让我很困惑。您可能只想在单个类型上定义“通用方法”,并将其嵌入到要提供这些方法的类型中。您说您遇到了问题“因为结构方法只能访问结构自身的字段”,但事实并非如此。如果将某些类型
Base
嵌入类型
A
B
中,则它们可以直接在其方法中访问导出的
Base
字段。如果
Base
有一个方法
One
并且你想覆盖它,你可以在
a
中重新定义它,并且仍然像在那些OO语言中一样在该上下文中调用
a.Base.One()
。我认为你需要给出一个更具体的例子,说明你正在尝试做什么,以及为什么你认为这种方法是必要的。我给了你一个向上投票来中和评级,因为我同意@william.taylor.09。除了你几乎不想使用指向接口的指针之外。您的
MyReadWriter
不应该使用指向接口的指针,而应该是
type MyReadWriter struct{Reader,Writer}
。这允许(例如)
rw:=MyReadWriter{strings.NewReader(“foo”),new(bytes.Buffer)}
。感谢大家的提醒,很高兴知道这一点。你有解释原因的链接吗?另外,这个例子是直接从有效的go页面上获得的。一个获得更多接口细节的好地方是。我必须仔细阅读,以注意您丢失的上下文。第一个示例显示了
io.Reader
io.Writer
的定义,它们是接口(还有一个接口)。后者显示了
*bufio.Reader
*bufio.Writer
,它们(都是指向结构类型的指针)嵌入到类型中以实现
io.ReadWriter
。这两篇摘录来自不同的软件包,你不能把它们剪切粘贴在一起。@DaveC,你说得对!我用固定的例子更新了答案。这是评论,不是问题的答案。