【问题标题】:Golang: what's the point of interfaces when you have multiple inheritence [closed]Golang:当你有多重继承时,接口有什么意义[关闭]
【发布时间】:2013-08-05 14:12:47
【问题描述】:

我是一名 Java 程序员,正在学习 Go 编程。到目前为止,我真的很喜欢这种语言。比 Java 多很多。

但有一件事我有点困惑。 Java 有接口,因为类只能从一个类继承。既然 Go 允许多重继承,那么接口的意义何在?

【问题讨论】:

  • 依我拙见,stackoverflow.com/questions/8531292/… 的答案也适用于此。
  • 接口和多重继承是相关的,但只是相切的。 Java 的接口不能替代多重继承。接口允许您将合同与实现分开。多重继承的用途有限,但会导致更多的麻烦和不直观、难以调试的问题,恕我直言。
  • @JimGarrison,你能详细说明一下吗?接口只是告诉“做什么”,而通过继承,您还可以获得有关“如何”做的信息,并可以选择覆盖该行为。继承怎么会造成麻烦,在什么场景下接口会更好。举个例子真的很有帮助!
  • the diamond inheritance problem 的变通方法已经做了很多工作。 Java 完全避免了这种情况。关于接口和继承之间区别的完整论文将占用比 SO 更多的空间。
  • 完全同意你的看法。 Java 避免了多重继承,因此需要接口。 Go 通过让你覆盖冲突的方法来启用多重继承。我的问题是接口在这种情况下的用途。原来是鸭子打字。我正在添加相同的答案

标签: java inheritance interface go multiple-inheritance


【解决方案1】:

多态性

接口使函数能够具有“占位符”参数,该参数可以将不同的结构作为参数。例如,如果结构体 Man、Woman、Child 实现接口 Human,那么带有参数 Human 的方法可以将结构体 Man、Woman、Child 中的任何一个作为参数。因此,接口参数可以“变形”为作为参数传递的任何结构,只要它实现了接口中定义的所有函数。

这很重要,因为接口是在 Go 中实现多态性的唯一方法,因为它没有继承。因此,如果 Man “扩展” Human(通过将其作为匿名字段),则任何使用 Human 作为参数的方法都无法将 Man 作为参数。

我的困惑源于继承也是在 Java 中实现多态性的一种方式,我认为这里也是如此。我的立场是正确的!

【讨论】:

    【解决方案2】:

    Go 中的接口与 Java 中的接口非常不同。

    在 Java 中,一个类必须正式同意实现一个接口:

    public class Foo implements iFoo
    

    在 Go 中,用户类型只需这样做即可实现接口。

    然后函数或属性可以定义预期的内容:

    func DoSomething(r io.Reader) {
        buf := make([]byte, 128)
        n, err := r.Read(buf)
        ...
    }
    

    DoSomething 函数可以传递 anything,它实现了 io.Reader 接口中的 Read 函数,而 thing 并不知道或关心该接口.调用者有责任确保它传递了实现接口的something。这是在编译时检查的。

    我们可以更进一步。我们可以定义自己的接口:

    type MyInterface interface {
        io.Reader // Include Reader interface
        Seek(int) error // Include my own function
    }
    func DoSomething(r MyInterface) {
        buf := make([]byte, 128)
        n, err := r.Read(buf)
        ...
    }
    

    Go 的不同之处还在于它没有 classobject 类型。任何用户声明的类型,无论是基于整数、字符串、结构、数组、切片、通道等,都可以附加方法。

    Go 也没有你通常习惯的典型的类继承,但它确实有一些非常接近的东西。

    重新声明的类型:

    type Num int
    
    func (n Num) Print() {
        print(n)
    }
    
    type Number Num
    
    func (n Number) Print() {
        Num(n).Print()
    }
    

    匿名字段:

    type Foo struct {
        sync.Mutex
    }
    
    func main() {
        f := Foo{}
        f.Lock()
        // ...
        f.Unlock()
    }
    

    【讨论】:

      【解决方案3】:

      如果超类型 X 是一个接口,那么维护代码的人会立即知道它没有方法实现。如果超类型 Y 是一个抽象类,那么维护代码的人必须检查是否有方法实现。所以这是一个文档/维护/可读性的事情。

      【讨论】:

        【解决方案4】:

        类可以从多个类文件继承和实现。

        除非我误解了:

        public class MyClass extends MySuperClass implements MyInterface, MySecondInterface
        

        接口的重点是允许一个完全抽象的类。如此抽象以至于没有定义一个方法。 当我需要创建几个具有相同基本结构的抽象类时,我会使用接口。然后,我将能够创建扩展抽象类的类的实例,而抽象类又将实现接口。

        这是通过接口java.util.Collection 完成的,而java.util.ArrayListjava.util.Stack 等一些类实现了该接口。这样您就可以将各种列表的项目存储在一个集合中。这就是为什么ArrayList 有一个addAll(Collection<? extends E> c) 的方法。

        你可以说它就像是向后兼容更简单的对象。

        【讨论】:

          猜你喜欢
          • 2017-03-27
          • 2012-04-15
          • 1970-01-01
          • 2018-11-17
          • 2015-06-27
          • 2017-11-01
          • 2010-11-04
          • 1970-01-01
          • 2013-03-31
          相关资源
          最近更新 更多