Go 面向对象编程篇:接口定义及实现

接口在 Go 语言中有着至关重要的地位,如果说 goroutine 和 channel 是支撑起 Go 语言并发模型的基石,那么接口就是 Go 语言整个类型系统的基石。

Go 语言的接口实现

一个类型只要实现了某个接口要求的所有方法,我们就说这个类实现了该接口。

例如,我们定义了一个 File 类,并实现了 Read()Write()Seek()Close() 四个方法:

type File struct { 
    // ...
}

func (f *File) Read(buf []byte) (n int, err error) 
func (f *File) Write(buf []byte) (n int, err error) 
func (f *File) Seek(off int64, whence int) (pos int64, err error) 
func (f *File) Close() error

假设我们有如下接口(Go 语言通过关键字 interface 来声明接口,以示和结构体类型的区别,花括号内包含的是待实现的方法集合):

type IFile interface { 
    Read(buf []byte) (n int, err error) 
    Write(buf []byte) (n int, err error) 
    Seek(off int64, whence int) (pos int64, err error) 
    Close() error 
}

type IReader interface { 
    Read(buf []byte) (n int, err error) 
}

type IWriter interface { 
    Write(buf []byte) (n int, err error) 
}

type ICloser interface { 
    Close() error 
}

尽管 File 类并没有显式实现这些接口,甚至根本不知道这些接口的存在,但是我们说 File 类实现了这些接口,因为 File 类实现了上述所有接口声明的方法。

与 Java , PHP 相对,我们把Go语言的这种接口称作非侵入式接口,因为类与接口的实现关系不是通过显示声明,而是通过根据方法集合进行判断。这样有两个好处:

  • 其一,Go语言的标准库不需要绘制类库的继承/实现树图,在Go语言中,类的继承树并无意义,你只需要知道这个类实现了哪些方法,每个方法是干什么的就足够了。
  • 其二,定义接口的时候,只需要关心自己应该提供哪些方法即可,不用再纠结接口需要拆得多细才合理,也不需要为了实现某个接口而引入接口所在的包,接口由使用方法按需定义,不用事先设计,也不用考虑之前是否有其他模块定义过类似接口。

通过组合实现接口继承

我们知道在 JavaPHP 等传统面向对象编程语言中,支持通过 extends 关键字实现接口之间的继承关系:

interface A 
{
    public function foo();
}

interface B extends A
{
    public function bar();
}

在上述代码中,我们定义了两个 PHP 接口:AB,其中接口 B 继承自 A,这样一来,如果某个类实现了接口 B,则必须实现这两个接口中声明的方法,否则会报错。

Go 语言也支持类似的「接口继承」特性,但是由于不支持 extends 关键字,所以其实现和类的继承一样,是通过组合来完成的。以上面这个 PHP 示例为例,在 Go 语言中,我们可以这样通过接口组合来实现接口继承,就像类的组合一样:

type A interface {
    Foo()
}

type B interface {
    A
    Bar()
}

然后我们定义一个类 T 实现接口 B

type T struct {}

func (t T) Foo() {
    fmt.Println("call Foo function from interface A.")
}

func (t T) Bar() {
    fmt.Println("call Bar function from interface B.")
}

不过,在 Go 语言中,又与传统的接口继承有些不同,因为接口实现不是强制的,是根据类实现的方法来动态判定的,比如我们上面的 T 类可以只实现 Foo 方法,也可以只实现 Bar 方法,也可以都不实现。如果只实现了 Foo 方法,则 T 实现了接口 A;如果只实现了 Bar 方法,则既没有实现接口 A 也没有实现接口 B,只有两个方法都实现了系统才会判定实现了接口 B

可以认为接口的组合是匿名类型组合(没有显示为组合类型设置对应的属性名称) 的一个特定场景,只不过接口只包含方法,不包含任何属性。Go语言底层很多包就是基于接口组合实现的,比如io里面的 Reader ,Writer,ReadWriter这些接口:

// Reader is the interface that wraps the basic Read method.
type Reader interface {
    Read(p []byte) (n int, err error)
}

// Writer is the interface that wraps the basic Write method.
type Writer interface {
    Write(p []byte) (n int, err error)
}

// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
    Reader
    Writer
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值