Golang:当你有多重继承时,接口的作用是什么?

huangapple go评论81阅读模式
英文:

Golang: what's the point of interfaces when you have multiple inheritence

问题

我是一个Java程序员,正在学习Go语言编程。到目前为止,我非常喜欢这门语言,比Java更喜欢。

但是有一件事情让我有点困惑。Java有接口是因为类只能继承一个类。既然Go允许多重继承,那接口的作用是什么呢?

英文:

I'm a Java programmer, learning to program in Go. So far I really like the language. A LOT more than Java.

But there's one thing I'm a bit confused about. Java has interfaces because classes can inherit only from one class. Since Go allows multiple inheritance, what's the point of interfaces?

答案1

得分: 12

多态性

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

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

我的困惑源于继承也是Java中实现多态性的一种方式,我错误地认为在这里也是如此。我承认我错了!

英文:

Polymorphism

Interfaces enable functions to have a 'placeholder' parameter which can take different structs as an argument. For example, if structs Man, Woman, Child implement interface Human, then a method with the parameter Human can take any of the structs Man, Woman, Child as an argument. Hence, the interface parameter can 'morph' into any struct passed as an argument as long as it implements all functions defined in the interface.

This is important because interfaces are the only way of achieving Polymorphism in Go, since it doesn't have inheritance. So if Man 'extended' Human (by having it as an anonymous field), any method that used Human as an argument, would not be able to take Man as an argument.

My confusion stemmed from the fact that inheritance is also a way of achieving Polymorphism in Java, and I assumed that was the case here as well. I stand corrected!

答案2

得分: 9

在Go语言中,接口与Java中的接口非常不同。

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

public class Foo implements iFoo

在Go中,用户类型通过简单地这样做来实现一个接口。

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

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

DoSomething函数可以传递任何实现了io.Reader接口中的Read函数的东西,而不需要这个东西知道或关心接口。调用者有责任确保传入的是实现了接口的某个东西。这在编译时进行检查。

我们可以进一步扩展这个概念。我们可以定义自己的接口:

type MyInterface interface {
    io.Reader // 包含Reader接口
    Seek(int) error // 包含自己的函数
}
func DoSomething(r MyInterface) {
    buf := make([]byte, 128)
    n, err := r.Read(buf)
    ...
}

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

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()
}
英文:

Interfaces in Go are very different from interfaces in Java.

In Java a class has to formally agree to implement an interface:

public class Foo implements iFoo

In Go a user type implements an interface by simply doing so.

A function or property can then define what is expected:

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

The DoSomething function can be passed anything that implements the Read function found in the io.Reader interface, without the thing knowing or caring about the interface. It is the responsibility of the caller to make sure it is passing in something that implements the interface. This is checked at compile time.

We can take this a step further. We can define our own interface:

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 is also different in that it doesn't have a class or object type. Any user declared type, whether it be based on an integer, string, struct, array, slice, channel, etc. can have methods attached to it.

Go also doesn't have typical class-like inheritance you're normally used to, but it does have a couple of things that are pretty close.

Redeclared type:

type Num int

func (n Num) Print() {
    print(n)
}

type Number Num

func (n Number) Print() {
    Num(n).Print()
}

Anonymous fields:

type Foo struct {
	sync.Mutex
}

func main() {
	f := Foo{}
	f.Lock()
	// ...
	f.Unlock()
}

答案3

得分: 1

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

英文:

If supertype X is an interface, whoever is maintaining the code knows at once that it has no method implementations. If supertype Y is an abstract class, whoever is maintaining the code has to check whether there are method implementations. So it's a documentation/maintenance/readability thing.

答案4

得分: 0

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

除非我理解错了:

public class MyClass extends MySuperClass implements MyInterface, MySecondInterface

接口的目的是允许创建一个完全抽象的类,抽象到没有定义任何方法。当我需要创建几个具有相同基本结构的抽象类时,我会使用接口。然后,我可以创建扩展该抽象类的类的实例,这些类又实现了该接口。

这就是使用接口java.util.Collection和一些类如java.util.ArrayListjava.util.Stack实现该接口的方式。这样,你可以将各种列表项存储在一个集合中。这就是为什么ArrayList有一个addAll(Collection<? extends E> c)方法。

你可以说这就像是与更简单的对象保持向后兼容。

英文:

Classes can inherit and implement from multiple class files.

Unless I misinterpreted:

public class MyClass extends MySuperClass implements MyInterface, MySecondInterface

The point of interfaces is to allow for a completely abstract class. So abstract that there isn't a single method defined.
I would use an interface when I need to create several abstract classes with the same basic structure. I would then be able to create instances of classes which extend the abstract class, which in turn would implement the interface.

This is done with the interface java.util.Collection and some classes like java.util.ArrayList and java.util.Stack implement that interface. This way you can store all kinds of lists' items in a Collection. This is why ArrayList has a method to addAll(Collection&lt;? extends E&gt; c).

You could say it is like being backwards compatible with simpler objects.

huangapple
  • 本文由 发表于 2013年8月5日 07:13:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/18048541.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定