接口篇(四):通过接口组合实现接口继承
我们知道在 PHP 中支持接口继承以提高代码复用性:
<?php
interface A
{
public function foo();
}
interface B extends A
{
public function bar();
}
class T implements B
{
public function foo()
{
// do something
}
public function bar()
{
// do something
}
}
在上述代码中,我们定义了两个 PHP 接口:A
和 B
,其中接口 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
,我们可以做这样的接口赋值:
var t = T{}
var a A = t
a.Foo()
这个时候不能将 t
赋值给 B
类型接口变量,因为它没有实现 Bar
方法,则系统判定 T
没有实现接口 B
,在编译时会报错:
cannot use t (type T) as type B in assignment:
T does not implement B (missing Bar method)
如果单独实现了 Bar
方法,则既没有实现接口 A
也没有实现接口 B
,只有都实现了系统才会判定实现了接口 B
,才能进行相应的接口赋值:
var t = T{}
var b B = t
b.Foo()
b.Bar()
可以认为接口组合是匿名类型组合(没有显式为组合类型设置对应的属性名称)的一个特定场景,只不过接口只包含方法,而不包含任何成员变量。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
}
No Comments