继承
首先 Go 不支持经典的面向对象编程范式,但是我们也会看到go中存在继承这种说法。其实这里的继承只是习惯性的使用了继承这个词而已,真正表达的意思是一种组合的思想。
这种组合是通过go的类型嵌入实现的。
类型嵌入
类型嵌入指的就是在一个类型的定义中嵌入了其他类型。Go 语言支持两种类型嵌入,分别 是接口类型的类型嵌入和结构体类型的类型嵌入。
接口类型的类型嵌入
go中的接口定义
1 | // 定义接口 |
定义了一个接口Programmer,他有两个方法WriteHello和Dance。如果某个类型实现了这两个方法,我们就说这个类型实现了接口Programmer。
如果我们再定义一个接口
1 | type GoProgrammer interface { |
接口GoProgrammer的方法集合中也有WriteHello和Dance,那么就可以用接口Programmer替换这两个方法。
1 | type GoProgrammer interface { |
这就是接口类型的类型嵌入。
并且这两种写法的GoProgrammer是等价的。也就是说方法的声明会组合到一起。
这种写法有什么好处呢?
按 Go 语言惯例,Go 中的接口类型中只包含少量方法,并且常常只是一个方法。通过在接 口类型中嵌入其他接口类型可以实现接口的组合,这也是 Go 语言中基于已有接口类型构建新接口类型的惯用法。
实这也是 Go 组合设计哲学的一种体现。
结构体类型的类型嵌入
我们之前讲结构体的时候举过一个例子
1 | type Reader struct { |
Book中的Reader就是一种结构体类型的类型嵌入
这种情况下,Reader的方法会被提升为Book的方法,成为Book方法集合的一部分。(之前的例子是属性,方法也是一样的原理)
1 | reader := Reader{"yunsheng", 20} |
可以省略嵌入的Reader字段,而直接访问ReaderName
这也是go语言组合设计思想的一种体现。更具体点说是组合中的代理模式。由Book的ReaderName代理了Book.Reader.ReaderName
如果Book和嵌入的Reader有同名的方法,通过book调用时,先查找Book是否有该方法,没有再查找嵌入的字段有没有该方法。