Inheritance 在Go中嵌入而不是继承

Inheritance 在Go中嵌入而不是继承,inheritance,go,embedding,Inheritance,Go,Embedding,你对这个设计决定有什么看法?它有什么优点和缺点 链接: 该公司的关键原则是“宁可合成也不要继承”;去吧,让你跟着它;-) 继承的唯一真正用途是: 多态性 Go的界面“静态鸭子类型”系统解决了这个问题 从另一个类借用实现 这就是嵌入的目的 GO方法不精确映射1-to-1,考虑java中继承和多态的经典例子: 在这里,继承和多态性是结合在一起的,如果不改变底层结构,就无法将其转换为其他形式 我还没有深入研究围棋,但我想它看起来是这样的: //roughly Go? .... no?

你对这个设计决定有什么看法?它有什么优点和缺点

链接:


该公司的关键原则是“宁可合成也不要继承”;去吧,让你跟着它;-)

继承的唯一真正用途是:

  • 多态性

    • Go的界面“静态鸭子类型”系统解决了这个问题
  • 从另一个类借用实现

    • 这就是嵌入的目的

GO方法不精确映射1-to-1,考虑java中继承和多态的经典例子:

在这里,继承和多态性是结合在一起的,如果不改变底层结构,就无法将其转换为其他形式

我还没有深入研究围棋,但我想它看起来是这样的:

//roughly Go? .... no?
//for illustrative purposes only; not likely to compile
//
//WARNING: This is totally wrong; it's programming Java in Go

type Account interface {
    AddToBalance(int)
    MaxWithdraw() int
}

func Deposit(account Account, amount int) {
    account.AddToBalance(amount)
}

func Withdraw(account Account, amount int) error {
    if account.MaxWithdraw() < amount {
        return errors.New("Overdraft!")
    }
    account.AddToBalance(-amount)
    return nil
}

type BankAccount {
    balance int
}

func (account *BankAccount) AddToBalance(amount int) {
    account.balance += amount;
}

type RegularAccount {
    *BankAccount
}

func (account *RegularAccount) MaxWithdraw() int {
    return account.balance //assuming it's allowed
}

type OverdraftAccount {
    *BankAccount
    overdraft int
}

func (account *OverdraftAccount) MaxWithdraw() int {
    return account.balance + account.overdraft
}
//大致走了吗。。。。不
//仅用于说明目的;不太可能编译
//
//警告:这是完全错误的;这是用围棋编程Java
类型帐户接口{
AddToBalance(内部)
maxdraw()int
}
本币存款(账户,金额整数){
账户余额(金额)
}
func取款(科目、金额整数)错误{
if account.maxdraw()<金额{
返回错误。新建(“透支!”)
}
账户.增加余额(-金额)
归零
}
类型银行账户{
平衡整数
}
func(账户*银行账户)账户余额(金额整数){
账户余额+=金额;
}
类型定期帐户{
*银行账户
}
func(帐户*regularcount)maxdraw()int{
return account.balance//假设允许
}
类型透支账户{
*银行账户
透支整数
}
func(帐户*透支帐户)maxDraw()int{
返回账户.余额+账户.透支
}

根据注释,这是一种完全错误的编码方式,因为人们在围棋中使用Java。如果一个人在围棋中写这样一个东西,它的组织结构可能会与此大不相同。

我刚才正在学习围棋,但既然你在征求意见,我将根据我目前所知道的提供一个。嵌入似乎是Go中许多其他东西的典型特征,这是对现有语言中已经完成的最佳实践的显式语言支持。例如,正如Alex Martelli指出的,“四人帮”说“更喜欢组合而不是继承”。Go不仅删除了继承,而且使组合比C++/Java/C#更容易、更强大


我一直被诸如“Go没有提供我在语言X中已经做不到的新功能”和“为什么我们需要另一种语言?”之类的评论所困扰。在我看来,从某种意义上说,Go没有提供任何以前在某些工作中无法完成的新功能,但从另一种意义上说,新的是,Go将促进和鼓励使用已经在使用其他语言的实践中使用的最佳技术。

在一篇评论中,您想知道嵌入的想法是否足以“完全取代继承”。我想对这个问题的答案是“是”。几年前,我非常简单地使用了一个名为Tcl的OO系统,它使用组合和委托来排除继承。Snit仍然与Go的方法有很大的不同,但在这一方面,他们有一些共同的哲学基础。它是一种连接功能和职责的机制,而不是类的层次结构

正如其他人所说,这实际上是关于语言设计者想要支持哪种编程实践。所有这些选择都有其利弊;我不认为“最佳实践”一词在这里一定适用。我们最终可能会看到有人为Go开发一个继承层


(对于任何熟悉Tcl的读者来说,我觉得Snit与语言的“感觉”比
[incr Tcl]
更接近。至少在我看来,Tcl是关于授权的。)

人们要求提供有关嵌入Go的信息链接

这里有一个“有效的Go”文档,其中讨论了嵌入,并提供了具体的示例

如果您已经很好地掌握了Go接口和类型,那么这个示例就更有意义了,但是如果您将接口视为一组方法的名称,并且将结构视为类似于C结构,则可以伪造它

有关结构的更多信息,请参见Go语言规范,其中明确提到结构的无名成员为嵌入类型:

到目前为止,我只把它作为一种方便的方式来使用,当一个字段名不会给源代码添加任何值时,可以将一个结构放到另一个结构中,而不必为内部结构使用字段名。在下面的编程练习中,我将提案类型绑定到具有提案和响应通道的类型中


嵌入提供了自动委派。这本身不足以取代继承,因为嵌入不提供任何形式的多态性。Go接口确实提供多态性,它们与您可能使用的接口有些不同(有些人将它们比作duck类型或结构类型)

在其他语言中,继承层次结构需要仔细设计,因为更改范围很广,因此很难执行。Go在提供强大替代方案的同时避免了这些陷阱

这里有一篇文章深入探讨了OOP与Go的关系:

我喜欢它

你使用的语言会影响你的思维模式。(只要让C程序员实现“字数统计”。他们可能会使用链表,然后切换到二叉树以提高性能。但每个Java/Ruby/Python程序员都会使用字典/哈希。这种语言对他们的大脑影响太大,以至于他们想不起使用任何其他数据结构。)

对于继承,您必须向下构建--从抽象的东西开始,然后根据具体情况将其子类化。你
//roughly Go? .... no?
//for illustrative purposes only; not likely to compile
//
//WARNING: This is totally wrong; it's programming Java in Go

type Account interface {
    AddToBalance(int)
    MaxWithdraw() int
}

func Deposit(account Account, amount int) {
    account.AddToBalance(amount)
}

func Withdraw(account Account, amount int) error {
    if account.MaxWithdraw() < amount {
        return errors.New("Overdraft!")
    }
    account.AddToBalance(-amount)
    return nil
}

type BankAccount {
    balance int
}

func (account *BankAccount) AddToBalance(amount int) {
    account.balance += amount;
}

type RegularAccount {
    *BankAccount
}

func (account *RegularAccount) MaxWithdraw() int {
    return account.balance //assuming it's allowed
}

type OverdraftAccount {
    *BankAccount
    overdraft int
}

func (account *OverdraftAccount) MaxWithdraw() int {
    return account.balance + account.overdraft
}